bool Test_MintAndSpend() { try { // This test assumes a list of coins were generated in Test_MintCoin() if (gCoins[0] == NULL) { // No coins: mint some. Test_MintCoin(); if (gCoins[0] == NULL) { return false; } } // Accumulate the list of generated coins into a fresh accumulator. // The first one gets marked as accumulated for a witness, the // others just get accumulated normally. Accumulator acc(&g_Params->accumulatorParams); AccumulatorWitness wAcc(g_Params, acc, gCoins[0]->getPublicCoin()); for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { acc += gCoins[i]->getPublicCoin(); wAcc +=gCoins[i]->getPublicCoin(); } // Now spend the coin SpendMetaData m(1,1); CDataStream cc(SER_NETWORK, PROTOCOL_VERSION); cc << *gCoins[0]; PrivateCoin myCoin(g_Params,cc); CoinSpend spend(g_Params, myCoin, acc, wAcc, m); // Serialize the proof and deserialize into newSpend CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << spend; gProofSize = ss.size(); CoinSpend newSpend(g_Params, ss); // See if we can verify the deserialized proof (return our result) bool ret = newSpend.Verify(acc, m); // Extract the serial number Bignum serialNumber = newSpend.getCoinSerialNumber(); gSerialNumberSize = ceil((double)serialNumber.bitSize() / 8.0); return ret; } catch (runtime_error &e) { cout << e.what() << endl; return false; } return false; }
Bignum generateRandomPrime(uint32_t primeBitLen, uint256 in_seed, uint256 *out_seed, uint32_t *prime_gen_counter) { // Verify that primeBitLen is not too small if (primeBitLen < 2) { throw ZerocoinException("Prime length is too short"); } // If primeBitLen < 33 bits, perform the base case. if (primeBitLen < 33) { Bignum result(0); // Set prime_seed = in_seed, prime_gen_counter = 0. uint256 prime_seed = in_seed; (*prime_gen_counter) = 0; // Loop up to "4 * primeBitLen" iterations. while ((*prime_gen_counter) < (4 * primeBitLen)) { // Generate a pseudorandom integer "c" of length primeBitLength bits uint32_t iteration_count; Bignum c = generateIntegerFromSeed(primeBitLen, prime_seed, &iteration_count); #ifdef ZEROCOIN_DEBUG cout << "generateRandomPrime: primeBitLen = " << primeBitLen << endl; cout << "Generated c = " << c << endl; #endif prime_seed += (iteration_count + 1); (*prime_gen_counter)++; // Set "intc" to be the least odd integer >= "c" we just generated uint32_t intc = c.getulong(); intc = (2 * floor(intc / 2.0)) + 1; #ifdef ZEROCOIN_DEBUG cout << "Should be odd. c = " << intc << endl; cout << "The big num is: c = " << c << endl; #endif // Perform trial division on this (relatively small) integer to determine if "intc" // is prime. If so, return success. if (primalityTestByTrialDivision(intc)) { // Return "intc" converted back into a Bignum and "prime_seed". We also updated // the variable "prime_gen_counter" in previous statements. result = intc; *out_seed = prime_seed; // Success return result; } } // while() // If we reached this point there was an error finding a candidate prime // so throw an exception. throw ZerocoinException("Unable to find prime in Shawe-Taylor algorithm"); // END OF BASE CASE } // If primeBitLen >= 33 bits, perform the recursive case. else { // Recurse to find a new random prime of roughly half the size uint32_t newLength = ceil((double)primeBitLen / 2.0) + 1; Bignum c0 = generateRandomPrime(newLength, in_seed, out_seed, prime_gen_counter); // Generate a random integer "x" of primeBitLen bits using the output // of the previous call. uint32_t numIterations; Bignum x = generateIntegerFromSeed(primeBitLen, *out_seed, &numIterations); (*out_seed) += numIterations + 1; // Compute "t" = ⎡x / (2 * c0⎤ // TODO no Ceiling call Bignum t = x / (Bignum(2) * c0); // Repeat the following procedure until we find a prime (or time out) for (uint32_t testNum = 0; testNum < MAX_PRIMEGEN_ATTEMPTS; testNum++) { // If ((2 * t * c0) + 1 > 2^{primeBitLen}), // then t = ⎡2^{primeBitLen} – 1 / (2 * c0)⎤. if ((Bignum(2) * t * c0) > (Bignum(2).pow(Bignum(primeBitLen)))) { t = ((Bignum(2).pow(Bignum(primeBitLen))) - Bignum(1)) / (Bignum(2) * c0); } // Set c = (2 * t * c0) + 1 Bignum c = (Bignum(2) * t * c0) + Bignum(1); // Increment prime_gen_counter (*prime_gen_counter)++; // Test "c" for primality as follows: // 1. First pick an integer "a" in between 2 and (c - 2) Bignum a = generateIntegerFromSeed(c.bitSize(), (*out_seed), &numIterations); a = Bignum(2) + (a % (c - Bignum(3))); (*out_seed) += (numIterations + 1); // 2. Compute "z" = a^{2*t} mod c Bignum z = a.pow_mod(Bignum(2) * t, c); // 3. Check if "c" is prime. // Specifically, verify that gcd((z-1), c) == 1 AND (z^c0 mod c) == 1 // If so we return "c" as our result. if (c.gcd(z - Bignum(1)).isOne() && z.pow_mod(c0, c).isOne()) { // Return "c", out_seed and prime_gen_counter // (the latter two of which were already updated) return c; } // 4. If the test did not succeed, increment "t" and loop t = t + Bignum(1); } // end of test loop } // We only reach this point if the test loop has iterated MAX_PRIMEGEN_ATTEMPTS // and failed to identify a valid prime. Throw an exception. throw ZerocoinException("Unable to generate random prime (too many tests)"); }
void CalculateParams(Params ¶ms, Bignum N, string aux, uint32_t securityLevel) { cout << "GNOSIS DEBUG: CalculateParams in ParamGeneration.cpp" << endl; params.initialized = false; params.accumulatorParams.initialized = false; cout << "GNOSIS DEBUG: aux is " << aux << endl; // Verify that |N| is > 1023 bits. uint32_t NLen = N.bitSize(); cout << "GNOSIS DEBUG: NLen is " << NLen << endl; if (NLen < 1023) { throw ZerocoinException("Modulus must be at least 1023 bits"); } // Verify that "securityLevel" is at least 80 bits (minimum). if (securityLevel < 80) { throw ZerocoinException("Security level must be at least 80 bits."); } cout << "GNOSIS DEBUG: securityLevel is " << securityLevel << endl; // Set the accumulator modulus to "N". params.accumulatorParams.accumulatorModulus = N; // Calculate the required size of the field "F_p" into which // we're embedding the coin commitment group. This may throw an // exception if the securityLevel is too large to be supported // by the current modulus. uint32_t pLen = 0; uint32_t qLen = 0; calculateGroupParamLengths(NLen - 2, securityLevel, &pLen, &qLen); // Calculate candidate parameters ("p", "q") for the coin commitment group // using a deterministic process based on "N", the "aux" string, and // the dedicated string "COMMITMENTGROUP". params.coinCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_COMMIT_GROUP), pLen, qLen); // g and h are invalid, since they are now different for each coin; see // "Rational Zero" by Garman et al., section 4.4. params.coinCommitmentGroup.invalidateGenerators(); PRINT_BIGNUM("params.coinCommitmentGroup.groupOrder", params.coinCommitmentGroup.groupOrder); PRINT_BIGNUM("params.coinCommitmentGroup.modulus", params.coinCommitmentGroup.modulus); // Next, we derive parameters for a second Accumulated Value commitment group. // This is a Schnorr group with the specific property that the order of the group // must be exactly equal to "q" from the commitment group. We set // the modulus of the new group equal to "2q+1" and test to see if this is prime. params.serialNumberSoKCommitmentGroup = deriveIntegerGroupFromOrder(params.coinCommitmentGroup.modulus); PRINT_GROUP_PARAMS(params.serialNumberSoKCommitmentGroup); // Calculate the parameters for the internal commitment // using the same process. params.accumulatorParams.accumulatorPoKCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_AIC_GROUP), qLen + 300, qLen + 1); PRINT_GROUP_PARAMS(params.accumulatorParams.accumulatorPoKCommitmentGroup); // Calculate the parameters for the accumulator QRN commitment generators. This isn't really // a whole group, just a pair of random generators in QR_N. uint32_t resultCtr; params.accumulatorParams.accumulatorQRNCommitmentGroup.g(generateIntegerFromSeed(NLen - 1, calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPG), &resultCtr).pow_mod(Bignum(2), N)); params.accumulatorParams.accumulatorQRNCommitmentGroup.h(generateIntegerFromSeed(NLen - 1, calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPH), &resultCtr).pow_mod(Bignum(2), N)); PRINT_BIGNUM("params.accumulatorParams.accumulatorQRNCommitmentGroup.g", params.accumulatorParams.accumulatorQRNCommitmentGroup.g()); PRINT_BIGNUM("params.accumulatorParams.accumulatorQRNCommitmentGroup.h", params.accumulatorParams.accumulatorQRNCommitmentGroup.h()); // Calculate the accumulator base, which we calculate as "u = C**2 mod N" // where C is an arbitrary value. In the unlikely case that "u = 1" we increment // "C" and repeat. Bignum constant(ACCUMULATOR_BASE_CONSTANT); params.accumulatorParams.accumulatorBase = Bignum(1); for (uint32_t count = 0; count < MAX_ACCUMGEN_ATTEMPTS && params.accumulatorParams.accumulatorBase.isOne(); count++) { params.accumulatorParams.accumulatorBase = constant.pow_mod(Bignum(2), params.accumulatorParams.accumulatorModulus); } // Compute the accumulator range. The upper range is the largest possible coin commitment value. // The lower range is sqrt(upper range) + 1. Since OpenSSL doesn't have // a square root function we use a slightly higher approximation. params.accumulatorParams.maxCoinValue = params.coinCommitmentGroup.modulus; params.accumulatorParams.minCoinValue = Bignum(2).pow((params.coinCommitmentGroup.modulus.bitSize() / 2) + 3); // If all went well, mark params as successfully initialized. params.accumulatorParams.initialized = true; // If all went well, mark params as successfully initialized. params.initialized = true; }