コード例 #1
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
void
calculateGroupParamLengths(uint32_t maxPLen, uint32_t securityLevel,
                           uint32_t *pLen, uint32_t *qLen)
{
	*pLen = *qLen = 0;

	if (securityLevel < 80) {
		throw ZerocoinException("Security level must be at least 80 bits.");
	} else if (securityLevel == 80) {
		*qLen = 256;
		*pLen = 1024;
	} else if (securityLevel <= 112) {
		*qLen = 256;
		*pLen = 2048;
	} else if (securityLevel <= 128) {
		*qLen = 320;
		*pLen = 3072;
	} else {
		throw ZerocoinException("Security level not supported.");
	}

	if (*pLen > maxPLen) {
		throw ZerocoinException("Modulus size is too small for this security level.");
	}
}
コード例 #2
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
Bignum
calculateGroupGenerator(Bignum serialNumber, uint256 seed, uint256 pSeed, uint256 qSeed, Bignum modulus, Bignum groupOrder, uint32_t index)
{
	Bignum result;

	// Verify that 0 <= index < 256
	if (index > 255) {
		throw ZerocoinException("Invalid index for group generation");
	}

	// Compute e = (modulus - 1) / groupOrder
	Bignum e = (modulus - Bignum(1)) / groupOrder;

	// Loop until we find a generator
	for (uint32_t count = 1; count < MAX_GENERATOR_ATTEMPTS; count++) {
		// hash = Hash(seed || pSeed || qSeed || “ggen” || index || count
		uint256 hash = (serialNumber > 0) ? calculateGeneratorSeed(serialNumber, "ggen", index, count)
		                                  : calculateGeneratorSeed(seed, pSeed, qSeed, "ggen", index, count);
		Bignum W(hash);

		// Compute result = W^e mod p
		result = W.pow_mod(e, modulus);

		// If result > 1, we have a generator
		if (result > 1) {
			return result;
		}
	}

	// We only get here if we failed to find a generator
	throw ZerocoinException("Unable to find a generator, too many attempts");
}
コード例 #3
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
IntegerGroupParams
deriveIntegerGroupFromOrder(Bignum &groupOrder)
{
	IntegerGroupParams result;

	// Set the order to "groupOrder"
	result.groupOrder = groupOrder;

	// Try possible values for "modulus" of the form "groupOrder * 2 * i" where
	// "p" is prime and i is a counter starting at 1.
	for (uint32_t i = 1; i < NUM_SCHNORRGEN_ATTEMPTS; i++) {
		// Set modulus equal to "groupOrder * 2 * i"
		result.modulus = (result.groupOrder * Bignum(i*2)) + Bignum(1);

		// Test the result for primality
		// TODO: This is a probabilistic routine and thus not the right choice
		if (result.modulus.isPrime(256)) {

			// Success.
			//
			// Calculate the generators "g", "h" using the process described in
			// NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q",
			// "domain_parameter_seed", "index"). We use "index" value 1
			// to generate "g" and "index" value 2 to generate "h".
			uint256 seed = calculateSeed(groupOrder, "", 128, "");
			uint256 pSeed = calculateHash(seed);
			uint256 qSeed = calculateHash(pSeed);
			result.g(calculateGroupGenerator(Bignum(0), seed, pSeed, qSeed, result.modulus, result.groupOrder, 1));
			result.h(calculateGroupGenerator(Bignum(0), seed, pSeed, qSeed, result.modulus, result.groupOrder, 2));

			// Perform some basic tests to make sure we have good parameters
			if (!(result.modulus.isPrime()) ||                          // modulus is prime
			        !(result.groupOrder.isPrime()) ||                       // order is prime
			        !((result.g().pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1
			        !((result.h().pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1
			        ((result.g().pow_mod(Bignum(100), result.modulus)).isOne()) ||        // g^100 mod modulus != 1
			        ((result.h().pow_mod(Bignum(100), result.modulus)).isOne()) ||        // h^100 mod modulus != 1
			        result.g() == result.h() ||                                 // g != h
			        result.g().isOne()) {                                       // g != 1
				// If any of the above tests fail, throw an exception
				throw ZerocoinException("Group parameters are not valid");
			}

			return result;
		}
	}

	// If we reached this point group generation has failed. Throw an exception.
	throw ZerocoinException("Too many attempts to generate Schnorr group.");
}
コード例 #4
0
//Accumulator class
Accumulator::Accumulator(const AccumulatorAndProofParams* p, const CoinDenomination d): params(p), denomination(d) {
	if (!(params->initialized)) {
		throw ZerocoinException("Invalid parameters for accumulator");
	}

	this->value = this->params->accumulatorBase;
}
コード例 #5
0
ファイル: Coin.cpp プロジェクト: Anoncoin/libzerocoin
void PrivateCoin::mintCoin(const CoinDenomination denomination) {
	// Repeat this process up to MAX_COINMINT_ATTEMPTS times until
	// we obtain a prime number
	for(uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {

		// Generate a random serial number in the range 0...{q-1} where
		// "q" is the order of the commitment group.
		Bignum s = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);

		// Generate a Pedersen commitment to the serial number "s"
		Commitment coin(&params->coinCommitmentGroup, s);

		// Now verify that the commitment is a prime number
		// in the appropriate range. If not, we'll throw this coin
		// away and generate a new one.
		if (coin.getCommitmentValue().isPrime(ZEROCOIN_MINT_PRIME_PARAM) &&
		        coin.getCommitmentValue() >= params->accumulatorParams.minCoinValue &&
		        coin.getCommitmentValue() <= params->accumulatorParams.maxCoinValue) {
			// Found a valid coin. Store it.
			this->serialNumber = s;
			this->randomness = coin.getRandomness();
			this->publicCoin = PublicCoin(params,coin.getCommitmentValue(), denomination);

			// Success! We're done.
			return;
		}
	}

	// We only get here if we did not find a coin within
	// MAX_COINMINT_ATTEMPTS. Throw an exception.
	throw ZerocoinException("Unable to mint a new Zerocoin (too many attempts)");
}
コード例 #6
0
Accumulator::Accumulator(const Params* p, const CoinDenomination d) {
	this->params = &(p->accumulatorParams);
	this->denomination = d;

	if (!(params->initialized)) {
		throw ZerocoinException("Invalid parameters for accumulator");
	}

	this->value = this->params->accumulatorBase;
}
コード例 #7
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
/// \brief Deterministically derives coin commitment group generators g & h from a serial number (and group modulus and order).
/// \param serialNumber                 Serial number of the ZC spend.
/// \param modulus                      Prime modulus for the field.
/// \param groupOrder                   Order of the group.
/// \param g_out						Out param for g generator.
/// \param h_out						Out param for h generator.
/// \throws                             A ZerocoinException if error.
///
/// The purpose of having different generators for each ZC spend is to prevent
/// one solution of the discrete log problem from allowing infinite double spends.
/// See "Rational Zero" by Garman et al., section 4.4 for more.
///
/// Unlike the other functions in this file, this is called after initial setup
/// of Zerocoin parameters (i.e., it is called during minting, spending, and verifying).
void
deriveGeneratorsFromSerialNumber(Bignum serialNumber, Bignum modulus, Bignum groupOrder, Bignum& g_out, Bignum& h_out)
{
	Bignum g, h;
	g = calculateGroupGenerator(serialNumber, 0, 0, 0, modulus, groupOrder, 1);
	h = calculateGroupGenerator(serialNumber, 0, 0, 0, modulus, groupOrder, 2);
	if (g == h) {
		throw ZerocoinException("g == h for coin commitment group generators derived from serial number");
	}
	g_out = g;
	h_out = h;
}
コード例 #8
0
void Accumulator::accumulate(const PublicCoin& coin) {
	// Make sure we're initialized
	if(!(this->value)) {
		throw ZerocoinException("Accumulator is not initialized");
	}

	if(this->denomination != coin.getDenomination()) {
		//std::stringstream msg;
		std::string msg;
		msg = "Wrong denomination for coin. Expected coins of denomination: ";
		msg += this->denomination;
		msg += ". Instead, got a coin of denomination: ";
		msg += coin.getDenomination();
		throw ZerocoinException(msg);
	}

	if(coin.validate()) {
		// Compute new accumulator = "old accumulator"^{element} mod N
		this->value = this->value.pow_mod(coin.getValue(), this->params->accumulatorModulus);
	} else {
		throw ZerocoinException("Coin is not valid");
	}
}
コード例 #9
0
ファイル: Coin.cpp プロジェクト: Anoncoin/libzerocoin
void PrivateCoin::mintCoinFast(const CoinDenomination denomination) {
	
	// Generate a random serial number in the range 0...{q-1} where
	// "q" is the order of the commitment group.
	Bignum s = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
	
	// Generate a random number "r" in the range 0...{q-1}
	Bignum r = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
	
	// Manually compute a Pedersen commitment to the serial number "s" under randomness "r"
	// C = g^s * h^r mod p
	Bignum commitmentValue = this->params->coinCommitmentGroup.g.pow_mod(s, this->params->coinCommitmentGroup.modulus).mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus);
	
	// Repeat this process up to MAX_COINMINT_ATTEMPTS times until
	// we obtain a prime number
	for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
		// First verify that the commitment is a prime number
		// in the appropriate range. If not, we'll throw this coin
		// away and generate a new one.
		if (commitmentValue.isPrime(ZEROCOIN_MINT_PRIME_PARAM) &&
			commitmentValue >= params->accumulatorParams.minCoinValue &&
			commitmentValue <= params->accumulatorParams.maxCoinValue) {
			// Found a valid coin. Store it.
			this->serialNumber = s;
			this->randomness = r;
			this->publicCoin = PublicCoin(params, commitmentValue, denomination);
				
			// Success! We're done.
			return;
		}
		
		// Generate a new random "r_delta" in 0...{q-1}
		Bignum r_delta = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);

		// The commitment was not prime. Increment "r" and recalculate "C":
		// r = r + r_delta mod q
		// C = C * h mod p
		r = (r + r_delta) % this->params->coinCommitmentGroup.groupOrder;
		commitmentValue = commitmentValue.mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r_delta, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus);
	}
		
	// We only get here if we did not find a coin within
	// MAX_COINMINT_ATTEMPTS. Throw an exception.
	throw ZerocoinException("Unable to mint a new Zerocoin (too many attempts)");
}
コード例 #10
0
ファイル: CoinSpend.cpp プロジェクト: Anoncoin/anoncoin
CoinSpend::CoinSpend(const Params* p, const PrivateCoin& coin,
                     Accumulator& a, const AccumulatorWitness& witness, const SpendMetaData& m):
	params(p),
	denomination(coin.getPublicCoin().getDenomination()),
	coinSerialNumber((coin.getSerialNumber())),
	accumulatorPoK(&p->accumulatorParams),
	serialNumberSoK(p),
	commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup) {

	// Sanity check: let's verify that the Witness is valid with respect to
	// the coin and Accumulator provided.
	if (!(witness.VerifyWitness(a, coin.getPublicCoin()))) {
		throw ZerocoinException("Accumulator witness does not verify");
	}

	// 1: Generate two separate commitments to the public coin (C), each under
	// a different set of public parameters. We do this because the RSA accumulator
	// has specific requirements for the commitment parameters that are not
	// compatible with the group we use for the serial number proof.
	// Specifically, our serial number proof requires the order of the commitment group
	// to be the same as the modulus of the upper group. The Accumulator proof requires a
	// group with a significantly larger order.
	const Commitment fullCommitmentToCoinUnderSerialParams(&p->serialNumberSoKCommitmentGroup, coin.getPublicCoin().getValue());
	this->serialCommitmentToCoinValue = fullCommitmentToCoinUnderSerialParams.getCommitmentValue();

	const Commitment fullCommitmentToCoinUnderAccParams(&p->accumulatorParams.accumulatorPoKCommitmentGroup, coin.getPublicCoin().getValue());
	this->accCommitmentToCoinValue = fullCommitmentToCoinUnderAccParams.getCommitmentValue();

	// 2. Generate a ZK proof that the two commitments contain the same public coin.
	this->commitmentPoK = CommitmentProofOfKnowledge(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup, fullCommitmentToCoinUnderSerialParams, fullCommitmentToCoinUnderAccParams);
	cout << "GNOSIS DEBUG: commitmentPoK is " << this->commitmentPoK.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) << " bytes" << endl;;

	// Now generate the two core ZK proofs:
	// 3. Proves that the committed public coin is in the Accumulator (PoK of "witness")
	this->accumulatorPoK = AccumulatorProofOfKnowledge(&p->accumulatorParams, fullCommitmentToCoinUnderAccParams, witness, a);
	cout << "GNOSIS DEBUG: accPoK is " << this->accumulatorPoK.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) << " bytes" << endl;;

	// 4. Proves that the coin is correct w.r.t. serial number and hidden coin secret
	// (This proof is bound to the coin 'metadata', i.e., transaction hash)
	this->serialNumberSoK = SerialNumberSignatureOfKnowledge(p, coin, fullCommitmentToCoinUnderSerialParams, signatureHash(m));
	cout << "GNOSIS DEBUG: snSoK is " << this->serialNumberSoK.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) << " bytes" << endl;;
}
コード例 #11
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
IntegerGroupParams
deriveIntegerGroupParams(uint256 seed, uint32_t pLen, uint32_t qLen)
{
	IntegerGroupParams result;
	Bignum p;
	Bignum q;
	uint256 pSeed, qSeed;

	// Calculate "p" and "q" and "domain_parameter_seed" from the
	// "seed" buffer above, using the procedure described in NIST
	// FIPS 186-3, Appendix A.1.2.
	calculateGroupModulusAndOrder(seed, pLen, qLen, &(result.modulus),
	                              &(result.groupOrder), &pSeed, &qSeed);

	// Calculate the generators "g", "h" using the process described in
	// NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q",
	// "domain_parameter_seed", "index"). We use "index" value 1
	// to generate "g" and "index" value 2 to generate "h".
	result.g(calculateGroupGenerator(Bignum(0), seed, pSeed, qSeed, result.modulus, result.groupOrder, 1));
	result.h(calculateGroupGenerator(Bignum(0), seed, pSeed, qSeed, result.modulus, result.groupOrder, 2));

	// Perform some basic tests to make sure we have good parameters
	if ((uint32_t)(result.modulus.bitSize()) < pLen ||          // modulus is pLen bits long
	        (uint32_t)(result.groupOrder.bitSize()) < qLen ||       // order is qLen bits long
	        !(result.modulus.isPrime()) ||                          // modulus is prime
	        !(result.groupOrder.isPrime()) ||                       // order is prime
	        !((result.g().pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1
	        !((result.h().pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1
	        ((result.g().pow_mod(Bignum(100), result.modulus)).isOne()) ||        // g^100 mod modulus != 1
	        ((result.h().pow_mod(Bignum(100), result.modulus)).isOne()) ||        // h^100 mod modulus != 1
	        result.g() == result.h() ||                                 // g != h
	        result.g().isOne()) {                                      // g != 1
		// If any of the above tests fail, throw an exception
		throw ZerocoinException("Group parameters are not valid");
	}

	return result;
}
コード例 #12
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
Bignum
calculateRawUFO(uint32_t ufoIndex, uint32_t numBits) {
	Bignum result(0);
	uint32_t hashes = numBits / HASH_OUTPUT_BITS;

	if (numBits != HASH_OUTPUT_BITS * hashes) {
		throw ZerocoinException("numBits must be divisible by HASH_OUTPUT_BITS");		// not implemented
	}

	for (uint32_t i = 0; i < hashes; i++) {
		CHashWriter hasher(0,0);
		hasher << ufoIndex;
		hasher << string("||");
		hasher << numBits;
		hasher << string("||");
		hasher << i;
		uint256 hash = hasher.GetHash();
		result <<= HASH_OUTPUT_BITS;
		result += Bignum(hash);
	}

	return result;
}
コード例 #13
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
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)");
}
コード例 #14
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
void
CalculateParams(Params &params, 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;
}
コード例 #15
0
ファイル: ParamGeneration.cpp プロジェクト: Anoncoin/anoncoin
void
calculateGroupModulusAndOrder(uint256 seed, uint32_t pLen, uint32_t qLen,
                              Bignum *resultModulus, Bignum *resultGroupOrder,
                              uint256 *resultPseed, uint256 *resultQseed)
{
	// Verify that the seed length is >= qLen
	if (qLen > (sizeof(seed)) * 8) {
		// TODO: The use of 256-bit seeds limits us to 256-bit group orders. We should probably change this.
		// throw ZerocoinException("Seed is too short to support the required security level.");
	}

#ifdef ZEROCOIN_DEBUG
	cout << "calculateGroupModulusAndOrder: pLen = " << pLen << endl;
#endif

	// Generate a random prime for the group order.
	// This may throw an exception, which we'll pass upwards.
	// Result is the value "resultGroupOrder", "qseed" and "qgen_counter".
	uint256     qseed;
	uint32_t    qgen_counter;
	*resultGroupOrder = generateRandomPrime(qLen, seed, &qseed, &qgen_counter);

	// Using ⎡pLen / 2 + 1⎤ as the length and qseed as the input_seed, use the random prime
	// routine to obtain p0 , pseed, and pgen_counter. We pass exceptions upward.
	uint32_t    p0len = ceil((pLen / 2.0) + 1);
	uint256     pseed;
	uint32_t    pgen_counter;
	Bignum p0 = generateRandomPrime(p0len, qseed, &pseed, &pgen_counter);

	// Set x = 0, old_counter = pgen_counter
	uint32_t    old_counter = pgen_counter;

	// Generate a random integer "x" of pLen bits
	uint32_t iterations;
	Bignum x = generateIntegerFromSeed(pLen, pseed, &iterations);
	pseed += (iterations + 1);

	// Set x = 2^{pLen−1} + (x mod 2^{pLen–1}).
	Bignum powerOfTwo = Bignum(2).pow(pLen-1);
	x = powerOfTwo + (x % powerOfTwo);

	// t = ⎡x / (2 * resultGroupOrder * p0)⎤.
	// TODO: we don't have a ceiling function
	Bignum t = x / (Bignum(2) * (*resultGroupOrder) * p0);

	// Now loop until we find a valid prime "p" or we fail due to
	// pgen_counter exceeding ((4*pLen) + old_counter).
	for ( ; pgen_counter <= ((4*pLen) + old_counter) ; pgen_counter++) {
		// If (2 * t * resultGroupOrder * p0 + 1) > 2^{pLen}, then
		// t = ⎡2^{pLen−1} / (2 * resultGroupOrder * p0)⎤.
		powerOfTwo = Bignum(2).pow(pLen);
		Bignum prod = (Bignum(2) * t * (*resultGroupOrder) * p0) + Bignum(1);
		if (prod > powerOfTwo) {
			// TODO: implement a ceil function
			t = Bignum(2).pow(pLen-1) / (Bignum(2) * (*resultGroupOrder) * p0);
		}

		// Compute a candidate prime resultModulus = 2tqp0 + 1.
		*resultModulus = (Bignum(2) * t * (*resultGroupOrder) * p0) + Bignum(1);

		// Verify that resultModulus is prime. First generate a pseudorandom integer "a".
		Bignum a = generateIntegerFromSeed(pLen, pseed, &iterations);
		pseed += iterations + 1;

		// Set a = 2 + (a mod (resultModulus–3)).
		a = Bignum(2) + (a % ((*resultModulus) - Bignum(3)));

		// Set z = a^{2 * t * resultGroupOrder} mod resultModulus
		Bignum z = a.pow_mod(Bignum(2) * t * (*resultGroupOrder), (*resultModulus));

		// If GCD(z–1, resultModulus) == 1 AND (z^{p0} mod resultModulus == 1)
		// then we have found our result. Return.
		if ((resultModulus->gcd(z - Bignum(1))).isOne() &&
		        (z.pow_mod(p0, (*resultModulus))).isOne()) {
			// Success! Return the seeds and primes.
			*resultPseed = pseed;
			*resultQseed = qseed;
			return;
		}

		// This prime did not work out. Increment "t" and try again.
		t = t + Bignum(1);
	} // loop continues until pgen_counter exceeds a limit

	// We reach this point only if we exceeded our maximum iteration count.
	// Throw an exception.
	throw ZerocoinException("Unable to generate a prime modulus for the group");
}