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.
22 using namespace libzerocoin;
23 extern Params* ZCParams;
26 #define TESTS_COINS_TO_ACCUMULATE 10
28 // Global test counters
29 uint32_t gNumTests = 0;
30 uint32_t gSuccessfulTests = 0;
33 uint32_t gProofSize = 0;
34 uint32_t gCoinSize = 0;
35 uint32_t gSerialNumberSize = 0;
38 PrivateCoin *gCoins[TESTS_COINS_TO_ACCUMULATE];
48 LogTestResult(string testName, bool (*testPtr)())
50 printf("Testing if %s ...\n", testName.c_str());
52 bool testResult = testPtr();
54 if (testResult == true) {
67 static Bignum testModulus(0);
69 // TODO: should use a hard-coded RSA modulus for testing
73 // Note: we are NOT using safe primes for testing because
74 // they take too long to generate. Don't do this in real
75 // usage. See the paramgen utility for better code.
76 p = Bignum::generatePrime(1024, false);
77 q = Bignum::generatePrime(1024, false);
91 Bignum result = GetTestModulus();
102 Test_CalcParamSizes()
110 calculateGroupParamLengths(4000, 80, &pLen, &qLen);
111 if (pLen < 1024 || qLen < 256) {
114 calculateGroupParamLengths(4000, 96, &pLen, &qLen);
115 if (pLen < 2048 || qLen < 256) {
118 calculateGroupParamLengths(4000, 112, &pLen, &qLen);
119 if (pLen < 3072 || qLen < 320) {
122 calculateGroupParamLengths(4000, 120, &pLen, &qLen);
123 if (pLen < 3072 || qLen < 320) {
126 calculateGroupParamLengths(4000, 128, &pLen, &qLen);
127 if (pLen < 3072 || qLen < 320) {
130 } catch (exception &e) {
139 Test_GenerateGroupParams()
141 int32_t pLen = 1024, qLen = 256, count;
142 IntegerGroupParams group;
144 for (count = 0; count < 1; count++) {
147 group = deriveIntegerGroupParams(calculateSeed(GetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen);
148 } catch (std::runtime_error e) {
149 printf("Caught exception %s\n", e.what());
153 // Now perform some simple tests on the resulting parameters
154 if (group.groupOrder.bitSize() < qLen || group.modulus.bitSize() < pLen) {
158 Bignum c = group.g.pow_mod(group.groupOrder, group.modulus);
159 if (!(c.isOne())) return false;
161 // Try at multiple parameter sizes
175 // Instantiating testParams runs the parameter generation code
176 Params testParams(GetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL);
177 } catch (runtime_error e) {
178 printf("ParamGen exception %s\n", e.what());
188 // This test assumes a list of coins were generated during
189 // the Test_MintCoin() test.
190 if (gCoins[0] == NULL) {
194 // Accumulate the coin list from first to last into one accumulator
195 Accumulator accOne(&g_Params->accumulatorParams);
196 Accumulator accTwo(&g_Params->accumulatorParams);
197 Accumulator accThree(&g_Params->accumulatorParams);
198 Accumulator accFour(&g_Params->accumulatorParams);
199 AccumulatorWitness wThree(g_Params, accThree, gCoins[0]->getPublicCoin());
201 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
202 accOne += gCoins[i]->getPublicCoin();
203 accTwo += gCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin();
204 accThree += gCoins[i]->getPublicCoin();
205 wThree += gCoins[i]->getPublicCoin();
207 accFour += gCoins[i]->getPublicCoin();
211 // Compare the accumulated results
212 if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) {
213 printf("Accumulators don't match\n");
217 if(accFour.getValue() != wThree.getValue()) {
218 printf("Witness math not working,\n");
222 // Verify that the witness is correct
223 if (!wThree.VerifyWitness(accThree, gCoins[0]->getPublicCoin()) ) {
224 printf("Witness not valid\n");
228 // Serialization test: see if we can serialize the accumulator
229 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
232 // Deserialize it into a new object
233 Accumulator newAcc(g_Params, ss);
235 // Compare the results
236 if (accOne.getValue() != newAcc.getValue()) {
240 } catch (runtime_error e) {
250 // Run this test 10 times
251 for (uint32_t i = 0; i < 10; i++) {
253 // Generate a random integer "val"
254 Bignum val = Bignum::randBignum(g_Params->coinCommitmentGroup.groupOrder);
256 // Manufacture two commitments to "val", both
257 // under different sets of parameters
258 Commitment one(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, val);
260 Commitment two(&g_Params->serialNumberSoKCommitmentGroup, val);
262 // Now generate a proof of knowledge that "one" and "two" are
263 // both commitments to the same value
264 CommitmentProofOfKnowledge pok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup,
265 &g_Params->serialNumberSoKCommitmentGroup,
268 // Serialize the proof into a stream
269 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
272 // Deserialize back into a PoK object
273 CommitmentProofOfKnowledge newPok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup,
274 &g_Params->serialNumberSoKCommitmentGroup,
277 if (newPok.Verify(one.getCommitmentValue(), two.getCommitmentValue()) != true) {
281 // Just for fun, deserialize the proof a second time
282 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
285 // This time tamper with it, then deserialize it back into a PoK
287 CommitmentProofOfKnowledge newPok2(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup,
288 &g_Params->serialNumberSoKCommitmentGroup,
291 // If the tampered proof verifies, that's a failure!
292 if (newPok2.Verify(one.getCommitmentValue(), two.getCommitmentValue()) == true) {
296 } catch (runtime_error &e) {
310 // Generate a list of coins
311 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
312 gCoins[i] = new PrivateCoin(g_Params);
314 PublicCoin pc = gCoins[i]->getPublicCoin();
315 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
317 gCoinSize += ss.size();
320 gCoinSize /= TESTS_COINS_TO_ACCUMULATE;
322 } catch (exception &e) {
333 // This test assumes a list of coins were generated in Test_MintCoin()
334 if (gCoins[0] == NULL)
336 // No coins: mint some.
338 if (gCoins[0] == NULL) {
343 // Accumulate the list of generated coins into a fresh accumulator.
344 // The first one gets marked as accumulated for a witness, the
345 // others just get accumulated normally.
346 Accumulator acc(&g_Params->accumulatorParams);
347 AccumulatorWitness wAcc(g_Params, acc, gCoins[0]->getPublicCoin());
349 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
350 acc += gCoins[i]->getPublicCoin();
351 wAcc +=gCoins[i]->getPublicCoin();
354 // Now spend the coin
355 SpendMetaData m(1,1);
357 CoinSpend spend(g_Params, *(gCoins[0]), acc, wAcc, m);
359 // Serialize the proof and deserialize into newSpend
360 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
362 gProofSize = ss.size();
363 CoinSpend newSpend(g_Params, ss);
365 // See if we can verify the deserialized proof (return our result)
366 bool ret = newSpend.Verify(acc, m);
368 // Extract the serial number
369 Bignum serialNumber = newSpend.getCoinSerialNumber();
370 gSerialNumberSize = ceil((double)serialNumber.bitSize() / 8.0);
373 } catch (runtime_error &e) {
374 printf("MintAndSpend exception %s\n", e.what());
384 printf("ZeroCoin v%s self-test routine\n", ZEROCOIN_VERSION_STRING);
386 // Make a new set of parameters from a random RSA modulus
387 //g_Params = new Params(GetTestModulus());
390 gNumTests = gSuccessfulTests = gProofSize = 0;
391 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
395 // Run through all of the Zerocoin tests
396 LogTestResult("an RSA modulus can be generated", Test_GenRSAModulus);
397 LogTestResult("parameter sizes are correct", Test_CalcParamSizes);
398 LogTestResult("group/field parameters can be generated", Test_GenerateGroupParams);
399 LogTestResult("parameter generation is correct", Test_ParamGen);
400 LogTestResult("coins can be minted", Test_MintCoin);
401 LogTestResult("the accumulator works", Test_Accumulator);
402 LogTestResult("the commitment equality PoK works", Test_EqualityPoK);
403 LogTestResult("a minted coin can be spent", Test_MintAndSpend);
405 printf("\nAverage coin size is %d bytes.\n", gCoinSize);
406 printf("Serial number size is %d bytes.\n", gSerialNumberSize);
407 printf("Spend proof size is %d bytes.\n", gProofSize);
409 // Summarize test results
410 if (gSuccessfulTests < gNumTests) {
411 printf("\nERROR: SOME TESTS FAILED\n");
414 // Clear any generated coins
415 for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) {
419 printf("\n%d out of %d tests passed.\n\n", gSuccessfulTests, gNumTests);