Skip to content

Commit 6288bb7

Browse files
committed
[Tests] PublicCoinSpend v4 / CRSchnorrSig unit tests
1 parent 7b81e54 commit 6288bb7

File tree

1 file changed

+212
-41
lines changed

1 file changed

+212
-41
lines changed

src/test/zerocoin_transactions_tests.cpp

Lines changed: 212 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "libzerocoin/Denominations.h"
66
#include "libzerocoin/Coin.h"
7+
#include "libzerocoin/CoinRandomnessSchnorrSignature.h"
78
#include "amount.h"
89
#include "chainparams.h"
910
#include "coincontrol.h"
@@ -56,64 +57,234 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test)
5657

5758
}
5859

60+
BOOST_AUTO_TEST_CASE(zerocoin_schnorr_signature_test)
61+
{
62+
const int NUM_OF_TESTS = 50;
63+
SelectParams(CBaseChainParams::MAIN);
64+
libzerocoin::ZerocoinParams *ZCParams_v1 = Params().Zerocoin_Params(true);
65+
(void)ZCParams_v1;
66+
libzerocoin::ZerocoinParams *ZCParams_v2 = Params().Zerocoin_Params(false);
67+
(void)ZCParams_v2;
68+
69+
for (int i=0; i<NUM_OF_TESTS; i++) {
70+
71+
// mint a v1 coin
72+
CBigNum s = CBigNum::randBignum(ZCParams_v1->coinCommitmentGroup.groupOrder);
73+
CBigNum r = CBigNum::randBignum(ZCParams_v1->coinCommitmentGroup.groupOrder);
74+
CBigNum c = ZCParams_v1->coinCommitmentGroup.g.pow_mod(s, ZCParams_v1->coinCommitmentGroup.modulus).mul_mod(
75+
ZCParams_v1->coinCommitmentGroup.h.pow_mod(r, ZCParams_v1->coinCommitmentGroup.modulus), ZCParams_v1->coinCommitmentGroup.modulus);
76+
for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
77+
if (c.isPrime(ZEROCOIN_MINT_PRIME_PARAM)) break;
78+
CBigNum r_delta = CBigNum::randBignum(ZCParams_v1->coinCommitmentGroup.groupOrder);
79+
r = (r + r_delta) % ZCParams_v1->coinCommitmentGroup.groupOrder;
80+
c = ZCParams_v1->coinCommitmentGroup.g.pow_mod(s, ZCParams_v1->coinCommitmentGroup.modulus).mul_mod(
81+
ZCParams_v1->coinCommitmentGroup.h.pow_mod(r, ZCParams_v1->coinCommitmentGroup.modulus), ZCParams_v1->coinCommitmentGroup.modulus);
82+
}
83+
BOOST_CHECK_MESSAGE(c.isPrime(ZEROCOIN_MINT_PRIME_PARAM), "Unable to mint v1 coin");
84+
libzerocoin::PrivateCoin privCoin_v1(ZCParams_v1, libzerocoin::CoinDenomination::ZQ_ONE, s, r);
85+
const CBigNum randomness_v1 = privCoin_v1.getRandomness();
86+
const CBigNum pubCoinValue_v1 = privCoin_v1.getPublicCoin().getValue();
87+
const CBigNum serialNumber_v1 = privCoin_v1.getSerialNumber();
88+
89+
// mint a v2 coin
90+
libzerocoin::PrivateCoin privCoin_v2(ZCParams_v2, libzerocoin::CoinDenomination::ZQ_ONE, true);
91+
const CBigNum randomness_v2 = privCoin_v2.getRandomness();
92+
const CBigNum pubCoinValue_v2 = privCoin_v2.getPublicCoin().getValue();
93+
const CBigNum serialNumber_v2 = privCoin_v2.getSerialNumber();
94+
95+
// get a random msghash
96+
const uint256 msghash = CBigNum::randKBitBignum(256).getuint256();
97+
98+
// sign the msghash with the randomness of the v1 coin
99+
libzerocoin::CoinRandomnessSchnorrSignature crss_v1(ZCParams_v1, randomness_v1, msghash);
100+
CDataStream ser_crss_v1(SER_NETWORK, PROTOCOL_VERSION);
101+
ser_crss_v1 << crss_v1;
102+
103+
// sign the msghash with the randomness of the v2 coin
104+
libzerocoin::CoinRandomnessSchnorrSignature crss_v2(ZCParams_v2, randomness_v2, msghash);
105+
CDataStream ser_crss_v2(SER_NETWORK, PROTOCOL_VERSION);
106+
ser_crss_v2 << crss_v2;
107+
108+
// unserialize the v1 signature into a fresh object and verify it
109+
libzerocoin::CoinRandomnessSchnorrSignature new_crss_v1(ser_crss_v1);
110+
BOOST_CHECK_MESSAGE(
111+
new_crss_v1.Verify(ZCParams_v1, serialNumber_v1, pubCoinValue_v1, msghash),
112+
"Failed to verify schnorr signature with v1 coin"
113+
);
114+
115+
// unserialize the v2 signature into a fresh object and verify it
116+
libzerocoin::CoinRandomnessSchnorrSignature new_crss_v2(ser_crss_v2);
117+
BOOST_CHECK_MESSAGE(
118+
new_crss_v2.Verify(ZCParams_v2, serialNumber_v2, pubCoinValue_v2, msghash),
119+
"Failed to verify schnorr signature with v2 coin"
120+
);
121+
122+
// verify failure on different msghash
123+
uint256 msghash2;
124+
do {
125+
msghash2 = CBigNum::randKBitBignum(256).getuint256();
126+
} while (msghash2 == msghash);
127+
BOOST_CHECK_MESSAGE(
128+
!new_crss_v1.Verify(ZCParams_v1, serialNumber_v1, pubCoinValue_v1, msghash2),
129+
"schnorr signature with v1 coin verifies on wrong msghash"
130+
);
131+
BOOST_CHECK_MESSAGE(
132+
!new_crss_v2.Verify(ZCParams_v2, serialNumber_v2, pubCoinValue_v2, msghash2),
133+
"schnorr signature with v2 coin verifies on wrong msghash"
134+
);
135+
136+
// verify failure swapping serials
137+
BOOST_CHECK_MESSAGE(
138+
!new_crss_v1.Verify(ZCParams_v1, serialNumber_v2, pubCoinValue_v1, msghash),
139+
"schnorr signature with v1 coin verifies on wrong serial"
140+
);
141+
BOOST_CHECK_MESSAGE(
142+
!new_crss_v2.Verify(ZCParams_v2, serialNumber_v1, pubCoinValue_v2, msghash),
143+
"schnorr signature with v2 coin verifies on wrong serial"
144+
);
145+
146+
// verify failure swapping public coins
147+
BOOST_CHECK_MESSAGE(
148+
!new_crss_v1.Verify(ZCParams_v1, serialNumber_v1, pubCoinValue_v2, msghash),
149+
"schnorr signature with v1 coin verifies on wrong public coin value"
150+
);
151+
BOOST_CHECK_MESSAGE(
152+
!new_crss_v2.Verify(ZCParams_v2, serialNumber_v2, pubCoinValue_v1, msghash),
153+
"schnorr signature with v2 coin verifies on wrong public coin value"
154+
);
155+
156+
}
157+
158+
}
159+
59160
BOOST_AUTO_TEST_CASE(zerocoin_public_spend_test)
60161
{
61162
SelectParams(CBaseChainParams::MAIN);
62-
libzerocoin::ZerocoinParams *ZCParams = Params().Zerocoin_Params(false);
63-
(void)ZCParams;
163+
libzerocoin::ZerocoinParams *ZCParams_v1 = Params().Zerocoin_Params(true);
164+
libzerocoin::ZerocoinParams *ZCParams_v2 = Params().Zerocoin_Params(false);
165+
(void)ZCParams_v1;
166+
(void)ZCParams_v2;
64167

65-
libzerocoin::PrivateCoin privCoin(ZCParams, libzerocoin::CoinDenomination::ZQ_ONE, true);
66-
const CPrivKey privKey = privCoin.getPrivKey();
168+
// create v1 coin
169+
CBigNum s = CBigNum::randBignum(ZCParams_v1->coinCommitmentGroup.groupOrder);
170+
CBigNum r = CBigNum::randBignum(ZCParams_v1->coinCommitmentGroup.groupOrder);
171+
CBigNum c = ZCParams_v1->coinCommitmentGroup.g.pow_mod(s, ZCParams_v1->coinCommitmentGroup.modulus).mul_mod(
172+
ZCParams_v1->coinCommitmentGroup.h.pow_mod(r, ZCParams_v1->coinCommitmentGroup.modulus), ZCParams_v1->coinCommitmentGroup.modulus);
173+
for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
174+
if (c.isPrime(ZEROCOIN_MINT_PRIME_PARAM)) break;
175+
CBigNum r_delta = CBigNum::randBignum(ZCParams_v1->coinCommitmentGroup.groupOrder);
176+
r = (r + r_delta) % ZCParams_v1->coinCommitmentGroup.groupOrder;
177+
c = ZCParams_v1->coinCommitmentGroup.g.pow_mod(s, ZCParams_v1->coinCommitmentGroup.modulus).mul_mod(
178+
ZCParams_v1->coinCommitmentGroup.h.pow_mod(r, ZCParams_v1->coinCommitmentGroup.modulus), ZCParams_v1->coinCommitmentGroup.modulus);
179+
}
180+
BOOST_CHECK_MESSAGE(c.isPrime(ZEROCOIN_MINT_PRIME_PARAM), "Unable to mint v1 coin");
181+
libzerocoin::PrivateCoin privCoin_v1(ZCParams_v1, libzerocoin::CoinDenomination::ZQ_ONE, s, r);
67182

68-
CZerocoinMint mint = CZerocoinMint(
69-
privCoin.getPublicCoin().getDenomination(),
70-
privCoin.getPublicCoin().getValue(),
71-
privCoin.getRandomness(),
72-
privCoin.getSerialNumber(),
183+
CZerocoinMint mint_v1 = CZerocoinMint(
184+
privCoin_v1.getPublicCoin().getDenomination(),
185+
privCoin_v1.getPublicCoin().getValue(),
186+
privCoin_v1.getRandomness(),
187+
privCoin_v1.getSerialNumber(),
73188
false,
74-
privCoin.getVersion(),
189+
1,
75190
nullptr);
76-
mint.SetPrivKey(privKey);
77191

192+
// create v2 coin
193+
libzerocoin::PrivateCoin privCoin_v2(ZCParams_v2, libzerocoin::CoinDenomination::ZQ_ONE, true);
194+
CPrivKey privKey = privCoin_v2.getPrivKey();
78195

79-
// Mint tx
80-
CTransaction prevTx;
196+
CZerocoinMint mint_v2 = CZerocoinMint(
197+
privCoin_v2.getPublicCoin().getDenomination(),
198+
privCoin_v2.getPublicCoin().getValue(),
199+
privCoin_v2.getRandomness(),
200+
privCoin_v2.getSerialNumber(),
201+
false,
202+
privCoin_v2.getVersion(),
203+
&privKey);
81204

82-
CScript scriptSerializedCoin = CScript()
83-
<< OP_ZEROCOINMINT << privCoin.getPublicCoin().getValue().getvch().size() << privCoin.getPublicCoin().getValue().getvch();
84-
CTxOut out = CTxOut(libzerocoin::ZerocoinDenominationToAmount(privCoin.getPublicCoin().getDenomination()), scriptSerializedCoin);
85-
prevTx.vout.push_back(out);
205+
// Mint txs
206+
CTransaction prevTx_v1;
207+
CTransaction prevTx_v2;
86208

87-
mint.SetOutputIndex(0);
88-
mint.SetTxHash(prevTx.GetHash());
209+
CScript scriptSerializedCoin_v1 = CScript()
210+
<< OP_ZEROCOINMINT << privCoin_v1.getPublicCoin().getValue().getvch().size() << privCoin_v1.getPublicCoin().getValue().getvch();
211+
CTxOut out_v1 = CTxOut(libzerocoin::ZerocoinDenominationToAmount(privCoin_v1.getPublicCoin().getDenomination()), scriptSerializedCoin_v1);
212+
prevTx_v1.vout.push_back(out_v1);
89213

90-
// Spend tx
91-
CMutableTransaction tx;
92-
tx.vout.resize(1);
93-
tx.vout[0].nValue = 1*CENT;
94-
tx.vout[0].scriptPubKey = GetScriptForDestination(CBitcoinAddress("D9Ti4LEhF1n6dR2hGd2SyNADD51AVgva6q").Get());
214+
CScript scriptSerializedCoin_v2 = CScript()
215+
<< OP_ZEROCOINMINT << privCoin_v2.getPublicCoin().getValue().getvch().size() << privCoin_v2.getPublicCoin().getValue().getvch();
216+
CTxOut out_v2 = CTxOut(libzerocoin::ZerocoinDenominationToAmount(privCoin_v2.getPublicCoin().getDenomination()), scriptSerializedCoin_v2);
217+
prevTx_v2.vout.push_back(out_v2);
95218

96-
CTxIn in;
97-
if (!ZPIVModule::createInput(in, mint, tx.GetHash())){
98-
BOOST_CHECK_MESSAGE(false, "Failed to create zc input");
99-
}
219+
mint_v1.SetOutputIndex(0);
220+
mint_v1.SetTxHash(prevTx_v1.GetHash());
100221

101-
PublicCoinSpend publicSpend(ZCParams);
102-
if (!ZPIVModule::validateInput(in, out, tx, publicSpend)){
103-
BOOST_CHECK_MESSAGE(false, "Failed to validate zc input");
104-
}
222+
mint_v2.SetOutputIndex(0);
223+
mint_v2.SetTxHash(prevTx_v2.GetHash());
224+
225+
// Spend txs
226+
CMutableTransaction tx1, tx2, tx3;
227+
tx1.vout.resize(1);
228+
tx1.vout[0].nValue = 1*CENT;
229+
tx1.vout[0].scriptPubKey = GetScriptForDestination(CBitcoinAddress("D9Ti4LEhF1n6dR2hGd2SyNADD51AVgva6q").Get());
230+
tx2.vout.resize(1);
231+
tx2.vout[0].nValue = 1*CENT;
232+
tx2.vout[0].scriptPubKey = GetScriptForDestination(CBitcoinAddress("D9Ti4LEhF1n6dR2hGd2SyNADD51AVgva6q").Get());
233+
tx3.vout.resize(1);
234+
tx3.vout[0].nValue = 1*CENT;
235+
tx3.vout[0].scriptPubKey = GetScriptForDestination(CBitcoinAddress("D9Ti4LEhF1n6dR2hGd2SyNADD51AVgva6q").Get());
236+
237+
CTxIn in1, in2, in3;
238+
239+
// check spendVersion = 3 for v2 coins
240+
// -----------------------------------
241+
int spendVersion = 3;
242+
BOOST_CHECK_MESSAGE(ZPIVModule::createInput(in1, mint_v2, tx1.GetHash(), spendVersion),
243+
"Failed to create zc input for mint v2 and spendVersion 3");
244+
245+
std::cout << "Spend v3 size: " << ::GetSerializeSize(in1, SER_NETWORK, PROTOCOL_VERSION) << " bytes" << std::endl;
246+
247+
PublicCoinSpend publicSpend1(ZCParams_v2);
248+
BOOST_CHECK_MESSAGE(ZPIVModule::validateInput(in1, out_v2, tx1, publicSpend1),
249+
"Failed to validate zc input for mint v2 and spendVersion 3");
250+
251+
// Verify that it fails with a different denomination
252+
in1.nSequence = 500;
253+
PublicCoinSpend publicSpend1b(ZCParams_v2);
254+
BOOST_CHECK_MESSAGE(!ZPIVModule::validateInput(in1, out_v2, tx1, publicSpend1b), "Different denomination for mint v2 and spendVersion 3");
255+
256+
// check spendVersion = 4 for v2 coins
257+
// -----------------------------------
258+
spendVersion = 4;
259+
BOOST_CHECK_MESSAGE(ZPIVModule::createInput(in2, mint_v2, tx2.GetHash(), spendVersion),
260+
"Failed to create zc input for mint v2 and spendVersion 4");
261+
262+
std::cout << "Spend v4 (coin v2) size: " << ::GetSerializeSize(in2, SER_NETWORK, PROTOCOL_VERSION) << " bytes" << std::endl;
263+
264+
PublicCoinSpend publicSpend2(ZCParams_v2);
265+
BOOST_CHECK_MESSAGE(ZPIVModule::validateInput(in2, out_v2, tx2, publicSpend2),
266+
"Failed to validate zc input for mint v2 and spendVersion 4");
267+
268+
// Verify that it fails with a different denomination
269+
in2.nSequence = 500;
270+
PublicCoinSpend publicSpend2b(ZCParams_v2);
271+
BOOST_CHECK_MESSAGE(!ZPIVModule::validateInput(in2, out_v2, tx2, publicSpend2b), "Different denomination for mint v2 and spendVersion 4");
272+
273+
// check spendVersion = 4 for v1 coins
274+
// -----------------------------------
275+
BOOST_CHECK_MESSAGE(ZPIVModule::createInput(in3, mint_v1, tx3.GetHash(), spendVersion),
276+
"Failed to create zc input for mint v1 and spendVersion 4");
105277

106-
PublicCoinSpend publicSpendTest(ZCParams);
107-
BOOST_CHECK_MESSAGE(ZPIVModule::parseCoinSpend(in, tx, out, publicSpendTest), "Failed to parse public spend");
108-
libzerocoin::CoinSpend *spend = &publicSpendTest;
278+
std::cout << "Spend v4 (coin v1) size: " << ::GetSerializeSize(in3, SER_NETWORK, PROTOCOL_VERSION) << " bytes" << std::endl;
109279

110-
BOOST_CHECK_MESSAGE(publicSpendTest.HasValidSignature(), "Failed to validate public spend signature");
111-
BOOST_CHECK_MESSAGE(spend->HasValidSignature(), "Failed to validate spend signature");
280+
PublicCoinSpend publicSpend3(ZCParams_v1);
281+
BOOST_CHECK_MESSAGE(ZPIVModule::validateInput(in3, out_v1, tx3, publicSpend3),
282+
"Failed to validate zc input for mint v1 and spendVersion 4");
112283

113-
// Verify that fails with a different denomination
114-
in.nSequence = 500;
115-
PublicCoinSpend publicSpend2(ZCParams);
116-
BOOST_CHECK_MESSAGE(!ZPIVModule::validateInput(in, out, tx, publicSpend2), "Different denomination");
284+
// Verify that it fails with a different denomination
285+
in3.nSequence = 500;
286+
PublicCoinSpend publicSpend3b(ZCParams_v1);
287+
BOOST_CHECK_MESSAGE(!ZPIVModule::validateInput(in3, out_v1, tx3, publicSpend3b), "Different denomination for mint v1 and spendVersion 4");
117288

118289
}
119290

0 commit comments

Comments
 (0)