4 * @brief Test routines for Zerocoin.
6 * @author Ian Miers, Christina Garman and Matthew Green
9 * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green
10 * @license This project is released under the MIT license.
23 using namespace libzerocoin;
24 extern Params* ZCParams;
26 #define COLOR_STR_GREEN "\033[32m"
27 #define COLOR_STR_NORMAL "\033[0m"
28 #define COLOR_STR_RED "\033[31m"
30 #define TESTS_COINS_TO_ACCUMULATE 10
32 // Global test counters
33 uint32_t gNumTests = 0;
34 uint32_t gSuccessfulTests = 0;
37 uint32_t gProofSize = 0;
38 uint32_t gCoinSize = 0;
39 uint32_t gSerialNumberSize = 0;
42 PrivateCoin *gCoins[TESTS_COINS_TO_ACCUMULATE];
52 LogTestResult(string testName, bool (*testPtr)())
54 printf("Testing if %s ...\n", testName.c_str());
56 bool testResult = testPtr();
58 if (testResult == true) {
71 static Bignum testModulus(0);
73 // TODO: should use a hard-coded RSA modulus for testing
77 // Note: we are NOT using safe primes for testing because
78 // they take too long to generate. Don't do this in real
79 // usage. See the paramgen utility for better code.
80 p = Bignum::generatePrime(1024, false);
81 q = Bignum::generatePrime(1024, false);
95 Bignum result = GetTestModulus();
106 Test_CalcParamSizes()
114 calculateGroupParamLengths(4000, 80, &pLen, &qLen);
115 if (pLen < 1024 || qLen < 256) {
118 calculateGroupParamLengths(4000, 96, &pLen, &qLen);
119 if (pLen < 2048 || qLen < 256) {
122 calculateGroupParamLengths(4000, 112, &pLen, &qLen);
123 if (pLen < 3072 || qLen < 320) {
126 calculateGroupParamLengths(4000, 120, &pLen, &qLen);
127 if (pLen < 3072 || qLen < 320) {
130 calculateGroupParamLengths(4000, 128, &pLen, &qLen);
131 if (pLen < 3072 || qLen < 320) {
134 } catch (exception &e) {
143 Test_GenerateGroupParams()
145 int32_t pLen = 1024, qLen = 256, count;
146 IntegerGroupParams group;
148 for (count = 0; count < 1; count++) {
151 group = deriveIntegerGroupParams(calculateSeed(GetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen);
152 } catch (std::runtime_error e) {
153 printf("Caught exception %s\n", e.what());
157 // Now perform some simple tests on the resulting parameters
158 if (group.groupOrder.bitSize() < qLen || group.modulus.bitSize() < pLen) {
162 Bignum c = group.g.pow_mod(group.groupOrder, group.modulus);
163 if (!(c.isOne())) return false;
165 // Try at multiple parameter sizes
179 // Instantiating testParams runs the parameter generation code
180 Params testParams(GetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL);
181 } catch (runtime_error e) {
182 printf("ParamGen exception %s\n", e.what());
192 // This test assumes a list of coins were generated during
193 // the Test_MintCoin() test.
194 if (gCoins[0] == NULL) {
198 // Accumulate the coin list from first to last into one accumulator
199 Accumulator accOne(&g_Params->accumulatorParams);
200 Accumulator accTwo(&g_Params->accumulatorParams);
201 Accumulator accThree(&g_Params->accumulatorParams);
202 Accumulator accFour(&g_Params->accumulatorParams);
203 AccumulatorWitness wThree(g_Params, accThree, gCoins[0]->getPublicCoin());
205 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
206 accOne += gCoins[i]->getPublicCoin();
207 accTwo += gCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin();
208 accThree += gCoins[i]->getPublicCoin();
209 wThree += gCoins[i]->getPublicCoin();
211 accFour += gCoins[i]->getPublicCoin();
215 // Compare the accumulated results
216 if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) {
217 printf("Accumulators don't match\n");
221 if(accFour.getValue() != wThree.getValue()) {
222 printf("Witness math not working,\n");
226 // Verify that the witness is correct
227 if (!wThree.VerifyWitness(accThree, gCoins[0]->getPublicCoin()) ) {
228 printf("Witness not valid\n");
232 // Serialization test: see if we can serialize the accumulator
233 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
236 // Deserialize it into a new object
237 Accumulator newAcc(g_Params, ss);
239 // Compare the results
240 if (accOne.getValue() != newAcc.getValue()) {
244 } catch (runtime_error e) {
254 // Run this test 10 times
255 for (uint32_t i = 0; i < 10; i++) {
257 // Generate a random integer "val"
258 Bignum val = Bignum::randBignum(g_Params->coinCommitmentGroup.groupOrder);
260 // Manufacture two commitments to "val", both
261 // under different sets of parameters
262 Commitment one(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, val);
264 Commitment two(&g_Params->serialNumberSoKCommitmentGroup, val);
266 // Now generate a proof of knowledge that "one" and "two" are
267 // both commitments to the same value
268 CommitmentProofOfKnowledge pok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup,
269 &g_Params->serialNumberSoKCommitmentGroup,
272 // Serialize the proof into a stream
273 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
276 // Deserialize back into a PoK object
277 CommitmentProofOfKnowledge newPok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup,
278 &g_Params->serialNumberSoKCommitmentGroup,
281 if (newPok.Verify(one.getCommitmentValue(), two.getCommitmentValue()) != true) {
285 // Just for fun, deserialize the proof a second time
286 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
289 // This time tamper with it, then deserialize it back into a PoK
291 CommitmentProofOfKnowledge newPok2(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup,
292 &g_Params->serialNumberSoKCommitmentGroup,
295 // If the tampered proof verifies, that's a failure!
296 if (newPok2.Verify(one.getCommitmentValue(), two.getCommitmentValue()) == true) {
300 } catch (runtime_error &e) {
314 // Generate a list of coins
315 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
316 gCoins[i] = new PrivateCoin(g_Params);
318 PublicCoin pc = gCoins[i]->getPublicCoin();
319 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
321 gCoinSize += ss.size();
324 gCoinSize /= TESTS_COINS_TO_ACCUMULATE;
326 } catch (exception &e) {
337 // This test assumes a list of coins were generated in Test_MintCoin()
338 if (gCoins[0] == NULL)
340 // No coins: mint some.
342 if (gCoins[0] == NULL) {
347 // Accumulate the list of generated coins into a fresh accumulator.
348 // The first one gets marked as accumulated for a witness, the
349 // others just get accumulated normally.
350 Accumulator acc(&g_Params->accumulatorParams);
351 AccumulatorWitness wAcc(g_Params, acc, gCoins[0]->getPublicCoin());
353 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
354 acc += gCoins[i]->getPublicCoin();
355 wAcc +=gCoins[i]->getPublicCoin();
358 // Now spend the coin
359 SpendMetaData m(1,1);
361 CoinSpend spend(g_Params, *(gCoins[0]), acc, wAcc, m);
363 // Serialize the proof and deserialize into newSpend
364 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
366 gProofSize = ss.size();
367 CoinSpend newSpend(g_Params, ss);
369 // See if we can verify the deserialized proof (return our result)
370 bool ret = newSpend.Verify(acc, m);
372 // Extract the serial number
373 Bignum serialNumber = newSpend.getCoinSerialNumber();
374 gSerialNumberSize = ceil((double)serialNumber.bitSize() / 8.0);
377 } catch (runtime_error &e) {
378 printf("MintAndSpend exception %s\n", e.what());
388 printf("ZeroCoin v%s self-test routine\n", ZEROCOIN_VERSION_STRING);
390 // Make a new set of parameters from a random RSA modulus
391 //g_Params = new Params(GetTestModulus());
394 gNumTests = gSuccessfulTests = gProofSize = 0;
395 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
399 // Run through all of the Zerocoin tests
400 LogTestResult("an RSA modulus can be generated", Test_GenRSAModulus);
401 LogTestResult("parameter sizes are correct", Test_CalcParamSizes);
402 LogTestResult("group/field parameters can be generated", Test_GenerateGroupParams);
403 LogTestResult("parameter generation is correct", Test_ParamGen);
404 LogTestResult("coins can be minted", Test_MintCoin);
405 LogTestResult("the accumulator works", Test_Accumulator);
406 LogTestResult("the commitment equality PoK works", Test_EqualityPoK);
407 LogTestResult("a minted coin can be spent", Test_MintAndSpend);
409 printf("\nAverage coin size is %d bytes.\n", gCoinSize);
410 printf("Serial number size is %d bytes.\n", gSerialNumberSize);
411 printf("Spend proof size is %d bytes.\n", gProofSize);
413 // Summarize test results
414 if (gSuccessfulTests < gNumTests) {
415 printf("\nERROR: SOME TESTS FAILED\n");
418 // Clear any generated coins
419 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
423 printf("\n%d out of %d tests passed.\n\n", gSuccessfulTests, gNumTests);