Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[zPIV] PublicCoinSpend v4 - Coin Randomness Schnorr Signature #936

Merged
merged 16 commits into from
Oct 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ set(ZEROCOIN_SOURCES
./src/libzerocoin/bignum.h
./src/libzerocoin/bignum.cpp
./src/libzerocoin/Coin.h
./src/libzerocoin/CoinRandomnessSchnorrSignature.h
./src/libzerocoin/CoinSpend.h
./src/libzerocoin/Commitment.h
./src/libzerocoin/Denominations.h
Expand All @@ -422,6 +423,7 @@ set(ZEROCOIN_SOURCES
./src/libzerocoin/Accumulator.cpp
./src/libzerocoin/AccumulatorProofOfKnowledge.cpp
./src/libzerocoin/Coin.cpp
./src/libzerocoin/CoinRandomnessSchnorrSignature.cpp
./src/libzerocoin/Denominations.cpp
./src/libzerocoin/CoinSpend.cpp
./src/libzerocoin/Commitment.cpp
Expand Down Expand Up @@ -572,11 +574,11 @@ target_include_directories(pivxd PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src
target_link_libraries(pivxd
pthread
SERVER_A
WALLET_A
COMMON_A
univalue
ZEROCOIN_A
UTIL_A
WALLET_A
BITCOIN_CRYPTO_A
${CMAKE_BINARY_DIR}/libleveldb.a
${CMAKE_BINARY_DIR}/libleveldb_sse42.a
Expand Down
4 changes: 3 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ libzerocoin_libbitcoin_zerocoin_a_SOURCES = \
libzerocoin/AccumulatorProofOfKnowledge.h \
libzerocoin/bignum.h \
libzerocoin/Coin.h \
libzerocoin/CoinRandomnessSchnorrSignature.h \
libzerocoin/CoinSpend.h \
libzerocoin/Commitment.h \
libzerocoin/Denominations.h \
Expand All @@ -348,9 +349,10 @@ libzerocoin_libbitcoin_zerocoin_a_SOURCES = \
libzerocoin/Accumulator.cpp \
libzerocoin/AccumulatorProofOfKnowledge.cpp \
libzerocoin/Coin.cpp \
libzerocoin/Denominations.cpp \
libzerocoin/CoinRandomnessSchnorrSignature.cpp \
libzerocoin/CoinSpend.cpp \
libzerocoin/Commitment.cpp \
libzerocoin/Denominations.cpp \
libzerocoin/ParamGeneration.cpp \
libzerocoin/Params.cpp \
libzerocoin/SerialNumberSignatureOfKnowledge.cpp
Expand Down
10 changes: 10 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ bool CChainParams::HasStakeMinAgeOrDepth(const int contextHeight, const uint32_t
return (contextHeight - utxoFromBlockHeight >= nStakeMinDepth);
}

int CChainParams::Zerocoin_PublicSpendVersion(const int nHeight) const
{
if (nHeight < nPublicZCSpendsV4)
return 3;
return 4;
}

class CMainParams : public CChainParams
{
public:
Expand Down Expand Up @@ -182,6 +189,7 @@ class CMainParams : public CChainParams
nBlockStakeModifierlV2 = 1967000;
// Public coin spend enforcement
nPublicZCSpends = 1880000;
nPublicZCSpendsV4 = 2880000;

// New P2P messages signatures
nBlockEnforceNewMessageSignatures = 2967000;
Expand Down Expand Up @@ -320,6 +328,7 @@ class CTestNetParams : public CMainParams
nBlockStakeModifierlV2 = 1214000;
// Public coin spend enforcement
nPublicZCSpends = 1106100;
nPublicZCSpendsV4 = 2106100;

// New P2P messages signatures
nBlockEnforceNewMessageSignatures = 2214000;
Expand Down Expand Up @@ -416,6 +425,7 @@ class CRegTestParams : public CTestNetParams
nBlockStakeModifierlV2 = std::numeric_limits<int>::max(); // max integer value (never switch on regtest)
// Public coin spend enforcement
nPublicZCSpends = 350;
nPublicZCSpendsV4 = 450;

// New P2P messages signatures
nBlockEnforceNewMessageSignatures = 1;
Expand Down
2 changes: 2 additions & 0 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class CChainParams
int Zerocoin_Block_V2_Start() const { return nBlockZerocoinV2; }
bool IsStakeModifierV2(const int nHeight) const { return nHeight >= nBlockStakeModifierlV2; }
int NewSigsActive(const int nHeight) const { return nHeight >= nBlockEnforceNewMessageSignatures; }
int Zerocoin_PublicSpendVersion(const int nHeight) const;

// fake serial attack
int Zerocoin_Block_EndFakeSerial() const { return nFakeSerialBlockheightEnd; }
Expand Down Expand Up @@ -223,6 +224,7 @@ class CChainParams
int nBlockZerocoinV2;
int nBlockDoubleAccumulated;
int nPublicZCSpends;
int nPublicZCSpendsV4;
int nBlockStakeModifierlV2;
int nBlockEnforceNewMessageSignatures;

Expand Down
16 changes: 8 additions & 8 deletions src/libzerocoin/AccumulatorProofOfKnowledge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndPro
CBigNum r = commitmentToCoin.getRandomness();

CBigNum aM_4 = params->accumulatorModulus/CBigNum((long)4);
CBigNum aR = CBigNum(2).pow(params->k_prime + params->k_dprime);
CBigNum aR = BN_TWO.pow(params->k_prime + params->k_dprime);
CBigNum aR_t_aM_4 = aM_4 * aR;

CBigNum r_1 = CBigNum::randBignum(aM_4);
Expand All @@ -43,7 +43,7 @@ AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndPro
this->C_r = g_n.pow_mod(r_2, params->accumulatorModulus) * h_n.pow_mod(r_3, params->accumulatorModulus);

CBigNum r_alpha = CBigNum::randBignum(params->maxCoinValue * aR);
if(!(CBigNum::randBignum(CBigNum(3)) % 2)) {
if(!(CBigNum::randBignum(BN_THREE) % 2)) {
r_alpha = 0-r_alpha;
}

Expand All @@ -54,24 +54,24 @@ AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndPro
CBigNum r_xi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);

CBigNum r_epsilon = CBigNum::randBignum(aR_t_aM_4);
if(!(CBigNum::randBignum(CBigNum(3)) % 2)) {
if(!(CBigNum::randBignum(BN_THREE) % 2)) {
r_epsilon = 0-r_epsilon;
}
CBigNum r_eta = CBigNum::randBignum(aR_t_aM_4);
if(!(CBigNum::randBignum(CBigNum(3)) % 2)) {
if(!(CBigNum::randBignum(BN_THREE) % 2)) {
r_eta = 0-r_eta;
}
CBigNum r_zeta = CBigNum::randBignum(aR_t_aM_4);
if(!(CBigNum::randBignum(CBigNum(3)) % 2)) {
if(!(CBigNum::randBignum(BN_THREE) % 2)) {
r_zeta = 0-r_zeta;
}

CBigNum r_beta = CBigNum::randBignum(aR_t_aM_4 * params->accumulatorPoKCommitmentGroup.modulus);
if(!(CBigNum::randBignum(CBigNum(3)) % 2)) {
if(!(CBigNum::randBignum(BN_THREE) % 2)) {
r_beta = 0-r_beta;
}
CBigNum r_delta = CBigNum::randBignum(aR_t_aM_4 * params->accumulatorPoKCommitmentGroup.modulus);
if(!(CBigNum::randBignum(CBigNum(3)) % 2)) {
if(!(CBigNum::randBignum(BN_THREE) % 2)) {
r_delta = 0-r_delta;
}

Expand Down Expand Up @@ -136,7 +136,7 @@ bool AccumulatorProofOfKnowledge:: Verify(const Accumulator& a, const CBigNum& v
bool result_t3 = (t_3 == t_3_prime);
bool result_t4 = (t_4 == t_4_prime);

bool result_range = ((s_alpha >= -(params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime + 1))) && (s_alpha <= (params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime + 1))));
bool result_range = ((s_alpha >= -(params->maxCoinValue * BN_TWO.pow(params->k_prime + params->k_dprime + 1))) && (s_alpha <= (params->maxCoinValue * BN_TWO.pow(params->k_prime + params->k_dprime + 1))));

return result_st1 && result_st2 && result_st3 && result_t1 && result_t2 && result_t3 && result_t4 && result_range;
}
Expand Down
10 changes: 9 additions & 1 deletion src/libzerocoin/Coin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,15 @@ bool IsValidSerial(const ZerocoinParams* params, const CBigNum& bnSerial)

bool IsValidCommitmentToCoinRange(const ZerocoinParams* params, const CBigNum& bnCommitment)
{
return bnCommitment > CBigNum(0) && bnCommitment < params->serialNumberSoKCommitmentGroup.modulus;
return bnCommitment > BN_ZERO && bnCommitment < params->serialNumberSoKCommitmentGroup.modulus;
}


CBigNum ExtractSerialFromPubKey(const CPubKey pubkey)
{
uint256 hashedPubkey = Hash(pubkey.begin(), pubkey.end()) >> PrivateCoin::V2_BITSHIFT;
uint256 uintSerial = (uint256(0xF) << (256 - PrivateCoin::V2_BITSHIFT)) | hashedPubkey;
return CBigNum(uintSerial);
}


Expand Down
1 change: 1 addition & 0 deletions src/libzerocoin/Coin.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace libzerocoin
bool IsValidSerial(const ZerocoinParams* params, const CBigNum& bnSerial);
bool IsValidCommitmentToCoinRange(const ZerocoinParams* params, const CBigNum& bnCommitment);
CBigNum GetAdjustedSerial(const CBigNum& bnSerial);
CBigNum ExtractSerialFromPubKey(const CPubKey pubkey);
bool GenerateKeyPair(const CBigNum& bnGroupOrder, const uint256& nPrivkey, CKey& key, CBigNum& bnSerial);

/** A Public coin is the part of a coin that
Expand Down
64 changes: 64 additions & 0 deletions src/libzerocoin/CoinRandomnessSchnorrSignature.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) 2019 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "CoinRandomnessSchnorrSignature.h"

namespace libzerocoin {

CoinRandomnessSchnorrSignature::CoinRandomnessSchnorrSignature(
const ZerocoinParams* zcparams, const CBigNum randomness, const uint256 msghash)
{
const CBigNum p = zcparams->coinCommitmentGroup.modulus;
const CBigNum q = zcparams->coinCommitmentGroup.groupOrder;
const CBigNum h = zcparams->coinCommitmentGroup.h;
const CBigNum pk = h.pow_mod(randomness, p);

alpha = 0;
beta = 0;

CBigNum k, r;

while (!alpha || !beta) {
// select random nonce k in Zq and let r = h^k mod p
k = CBigNum::randBignum(q);
r = h.pow_mod(k, p);

// challenge hash
CHashWriter hasher(0,0);
hasher << *zcparams << pk << r << msghash;
alpha = CBigNum(hasher.GetHash()) % q;
beta = (k - alpha.mul_mod(randomness, q)) % q;
}

}

bool CoinRandomnessSchnorrSignature::Verify(
const ZerocoinParams* zcparams, const CBigNum& S, const CBigNum& C, const uint256 msghash) const
{
const CBigNum p = zcparams->coinCommitmentGroup.modulus;
const CBigNum q = zcparams->coinCommitmentGroup.groupOrder;
const CBigNum h = zcparams->coinCommitmentGroup.h;
const CBigNum g = zcparams->coinCommitmentGroup.g;

// Params validation.
if (!IsValidSerial(zcparams, S)) return error("%s: Invalid serial range", __func__);
if (alpha < BN_ZERO || alpha >= q) return error("%s: alpha out of range", __func__);
if (beta < BN_ZERO || beta >= q) return error("%s: beta out of range", __func__);

// Schnorr public key computation.
const CBigNum pk = C.mul_mod(g.pow_mod(-S,p),p);

// Signature verification.
const CBigNum rv = (pk.pow_mod(alpha,p)).mul_mod(h.pow_mod(beta,p),p);
CHashWriter hasher(0,0);
hasher << *zcparams << pk << rv << msghash;

if (CBigNum(hasher.GetHash()) % q != alpha)
return error("%s: Schnorr signature does not verify", __func__);

return true;

}

} /* namespace libzerocoin */
56 changes: 56 additions & 0 deletions src/libzerocoin/CoinRandomnessSchnorrSignature.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2019 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef COINRANDOMNESSPROOF_H_
#define COINRANDOMNESSPROOF_H_

#include "Params.h"
#include "Coin.h"
#include "serialize.h"
#include "hash.h"

namespace libzerocoin {

/**A Schnorr Signature on the hash of metadata attesting that the signer knows the randomness v
* necessary to open a public coin C (which is a pedersen commitment g^S h^v mod p) with
* given serial number S.
*/
class CoinRandomnessSchnorrSignature {
public:
CoinRandomnessSchnorrSignature() {};
template <typename Stream> CoinRandomnessSchnorrSignature(Stream& strm) {strm >> *this;}

/** Creates a Schnorr signature object using the randomness of a public coin as private key sk.
*
* @param zcparams zerocoin params (group modulus, order and generators)
* @param randomness the coin we are going to use for the signature (sk := randomness, pk := h^sk mod p).
* @param msghash hash of meta data to create a signature on.
*/
CoinRandomnessSchnorrSignature(const ZerocoinParams* zcparams, const CBigNum randomness, const uint256 msghash);

/** Verifies the Schnorr signature on message msghash with public key pk = Cg^-S mod p
*
* @param zcparams zerocoin params (group modulus, order and generators)
* @param S serial number of the coin used for the signature
* @param C value of the public coin (commitment to serial S and randomness v) used for the signature.
* @param msghash hash of meta data to verify the signature on.
* @return
*/
bool Verify(const ZerocoinParams* zcparams, const CBigNum& S, const CBigNum& C, const uint256 msghash) const;

ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
{
READWRITE(alpha);
READWRITE(beta);
}

private:
// signature components
CBigNum alpha, beta;
};

} /* namespace libzerocoin */
#endif /* COINRANDOMNESSPROOF_H_ */
12 changes: 10 additions & 2 deletions src/libzerocoin/CoinSpend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,9 @@ bool CoinSpend::HasValidSerial(ZerocoinParams* params) const
//Additional verification layer that requires the spend be signed by the private key associated with the serial
bool CoinSpend::HasValidSignature() const
{
const int coinVersion = getCoinVersion();
//No private key for V1
if (version < PrivateCoin::PUBKEY_VERSION)
if (coinVersion < PrivateCoin::PUBKEY_VERSION)
return true;

try {
Expand All @@ -154,7 +155,7 @@ bool CoinSpend::HasValidSignature() const
CBigNum CoinSpend::CalculateValidSerial(ZerocoinParams* params)
{
CBigNum bnSerial = coinSerialNumber;
bnSerial = bnSerial.mul_mod(CBigNum(1),params->coinCommitmentGroup.groupOrder);
bnSerial = bnSerial % params->coinCommitmentGroup.groupOrder;
return bnSerial;
}

Expand All @@ -168,4 +169,11 @@ std::vector<unsigned char> CoinSpend::ParseSerial(CDataStream& s) {
return coinSerialNumber.getvch();
}

void CoinSpend::setPubKey(CPubKey pkey, bool fUpdateSerial) {
this->pubkey = pkey;
if (fUpdateSerial) {
this->coinSerialNumber = libzerocoin::ExtractSerialFromPubKey(this->pubkey);
}
}

} /* namespace libzerocoin */
5 changes: 3 additions & 2 deletions src/libzerocoin/CoinSpend.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ class CoinSpend
strm >> *this;

//Need to reset some parameters if v2
int serialVersion = ExtractVersionFromSerial(coinSerialNumber);
if (serialVersion >= PrivateCoin::PUBKEY_VERSION) {
if (getCoinVersion() >= PrivateCoin::PUBKEY_VERSION) {
accumulatorPoK = AccumulatorProofOfKnowledge(&paramsV2->accumulatorParams);
serialNumberSoK = SerialNumberSignatureOfKnowledge(paramsV2);
commitmentPoK = CommitmentProofOfKnowledge(&paramsV2->serialNumberSoKCommitmentGroup, &paramsV2->accumulatorParams.accumulatorPoKCommitmentGroup);
Expand Down Expand Up @@ -118,6 +117,7 @@ class CoinSpend
CBigNum getAccCommitment() const { return accCommitmentToCoinValue; }
CBigNum getSerialComm() const { return serialCommitmentToCoinValue; }
uint8_t getVersion() const { return version; }
int getCoinVersion() const { return libzerocoin::ExtractVersionFromSerial(coinSerialNumber); }
CPubKey getPubKey() const { return pubkey; }
SpendType getSpendType() const { return spendType; }
std::vector<unsigned char> getSignature() const { return vchSig; }
Expand All @@ -130,6 +130,7 @@ class CoinSpend
bool HasValidSignature() const;
void setTxOutHash(uint256 txOutHash) { this->ptxHash = txOutHash; };
void setDenom(libzerocoin::CoinDenomination denom) { this->denomination = denom; }
void setPubKey(CPubKey pkey, bool fUpdateSerial = false);

CBigNum CalculateValidSerial(ZerocoinParams* params);
std::string ToString() const;
Expand Down
13 changes: 7 additions & 6 deletions src/libzerocoin/Commitment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams*
uint32_t randomSize = COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN +
std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()),
std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize()));
CBigNum maxRange = (CBigNum(2).pow(randomSize) - CBigNum(1));

CBigNum maxRange = (BN_TWO.pow(randomSize) - BN_ONE);

r1 = CBigNum::randBignum(maxRange);
r2 = CBigNum::randBignum(maxRange);
Expand Down Expand Up @@ -114,11 +115,11 @@ bool CommitmentProofOfKnowledge::Verify(const CBigNum& A, const CBigNum& B) cons
if ((uint32_t)this->S1.bitSize() > maxSize ||
(uint32_t)this->S2.bitSize() > maxSize ||
(uint32_t)this->S3.bitSize() > maxSize ||
this->S1 < CBigNum(0) ||
this->S2 < CBigNum(0) ||
this->S3 < CBigNum(0) ||
this->challenge < CBigNum(0) ||
this->challenge > (CBigNum(2).pow(COMMITMENT_EQUALITY_CHALLENGE_SIZE) - CBigNum(1))) {
this->S1 < BN_ZERO ||
this->S2 < BN_ZERO ||
this->S3 < BN_ZERO ||
this->challenge < BN_ZERO ||
this->challenge > (BN_TWO.pow(COMMITMENT_EQUALITY_CHALLENGE_SIZE) - BN_ONE)) {
// Invalid inputs. Reject.
return false;
}
Expand Down