Exemple #1
0
  Bignum Bignum::operator*(const Bignum & bn) const {
    Bignum tmp; short symbol = 0, bit;
    const Bignum & self = *this;
    Bignum::Info info = Bignum::Info(self, bn);

    if (self[info.a_index] < 0) { symbol ^= 1; }
    if (bn[info.b_index] < 0) { symbol ^= 1; }

    self[info.a_index] = llabs(self[info.a_index]);
    bn[info.b_index] = llabs(bn[info.b_index]);

    for (int i = bignum_len - 1; i >= info.a_index; i--) {
      for (int j = bignum_len - 1; j >= info.b_index; j--) {
        bit = i - ( (bignum_len - 1) - j);
        tmp[bit] += (self[i] * bn[j]);
        tmp.carry(bit);
      }
    }

    if (symbol) {
      tmp[-tmp.bignum_used_len()] *= -1;
    }

    return tmp;
  }
Exemple #2
0
bool CommitmentProofOfKnowledge::Verify(const Bignum& A, const Bignum& B) const
{
    // TODO: First verify that the values
    // S1, S2 and S3 and "challenge" are in the correct ranges
    if((this->challenge < Bignum(0)) || (this->challenge > (Bignum(2).pow(256) - Bignum(1)))){
        return false;
    }
    
    // Compute T1 = g1^S1 * h1^S2 * inverse(A^{challenge}) mod p1
    Bignum T1 = A.pow_mod(this->challenge, ap->modulus).inverse(ap->modulus).mul_mod(
                                                                         (ap->g.pow_mod(S1, ap->modulus).mul_mod(ap->h.pow_mod(S2, ap->modulus), ap->modulus)),
                                                                         ap->modulus);
    
    // Compute T2 = g2^S1 * h2^S3 * inverse(B^{challenge}) mod p2
    Bignum T2 = B.pow_mod(this->challenge, bp->modulus).inverse(bp->modulus).mul_mod(
                                                                         (bp->g.pow_mod(S1, bp->modulus).mul_mod(bp->h.pow_mod(S3, bp->modulus), bp->modulus)),
                                                                         bp->modulus);
    
    // Hash T1 and T2 along with all of the public parameters
    Bignum computedChallenge = calculateChallenge(A, B, T1, T2);
    
    // Return success if the computed challenge matches the incoming challenge
    if(computedChallenge == this->challenge){
        return true;
    }
    
    // Otherwise return failure
    return false;
}
Exemple #3
0
  int rb_big_sign(VALUE obj) {
    NativeMethodEnvironment* env = NativeMethodEnvironment::get();

    Bignum* big = c_as<Bignum>(env->get_object(obj));

    return big->mp_val()->sign != MP_NEG;
  }
Exemple #4
0
  void test_coerce_bignum() {
    Fixnum* one = Fixnum::from(1);
    Bignum* e = Bignum::create(state, one);
    Array* ary = one->coerce(state, e);

    Fixnum* a = try_as<Fixnum>(ary->get(state, 0));
    Fixnum* b = try_as<Fixnum>(ary->get(state, 1));

    TS_ASSERT_EQUALS(2, ary->size());
    TS_ASSERT(a);
    TS_ASSERT(b);
    TS_ASSERT_EQUALS(one, a);
    TS_ASSERT_EQUALS(one, b);

    Bignum* f = Bignum::from(state, 9223372036854775807LL);
    ary = one->coerce(state, f);
    Bignum* c = try_as<Bignum>(ary->get(state, 0));
    Bignum* d = try_as<Bignum>(ary->get(state, 1));

    TS_ASSERT_EQUALS(2, ary->size());
    TS_ASSERT(c);
    TS_ASSERT(d);
    TS_ASSERT_EQUALS(cTrue, c->equal(state, f));
    TS_ASSERT_EQUALS(cTrue, d->equal(state, e));
  }
Exemple #5
0
  int rb_big_bytes_used(VALUE obj) {
    NativeMethodEnvironment* env = NativeMethodEnvironment::get();

    Bignum* big = c_as<Bignum>(env->get_object(obj));

    return big->size(env->state())->to_native();
  }
Exemple #6
0
bool
Test_GenerateGroupParams()
{
	uint32_t pLen = 1024, qLen = 256, count;
	IntegerGroupParams group;

	for (count = 0; count < 1; count++) {

		try {
			group = deriveIntegerGroupParams(calculateSeed(GetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen);
		} catch (std::runtime_error e) {
			cout << "Caught exception " << e.what() << endl;
			return false;
		}

		// Now perform some simple tests on the resulting parameters
		if (group.groupOrder.bitSize() < qLen || group.modulus.bitSize() < pLen) {
			return false;
		}

		Bignum c = group.g.pow_mod(group.groupOrder, group.modulus);
		//cout << "g^q mod p = " << c << endl;
		if (!(c.isOne())) return false;

		// Try at multiple parameter sizes
		pLen = pLen * 1.5;
		qLen = qLen * 1.5;
	}

	return true;
}
Exemple #7
0
  void test_mul_with_bignum() {
    Fixnum*  one   = as<Fixnum>(Fixnum::from(2));
    Bignum* two   = Bignum::from(state, (native_int)FIXNUM_MAX + 10);
    Integer* three = one->mul(state, two);

    TS_ASSERT_EQUALS(three->class_object(state), G(bignum));
    Bignum* expected = as<Bignum>(two->mul(state, Fixnum::from(2)));

    TS_ASSERT_EQUALS(cTrue, as<Bignum>(three)->equal(state, expected));
  }
Exemple #8
0
 void test_get_type() {
   TS_ASSERT_EQUALS(Qnil->get_type(), NilType);
   TS_ASSERT_EQUALS(Qtrue->get_type(), TrueType);
   TS_ASSERT_EQUALS(Qfalse->get_type(), FalseType);
   TS_ASSERT_EQUALS(state->symbol("blah")->get_type(), SymbolType);
   Object* obj = util_new_object();
   Bignum* big = Bignum::from(state, (native_int)13);
   TS_ASSERT_EQUALS(obj->get_type(), ObjectType);
   TS_ASSERT_EQUALS(big->get_type(), BignumType);
 }
Exemple #9
0
  double rb_big2dbl(VALUE obj) {
    NativeMethodEnvironment* env = NativeMethodEnvironment::get();

    Bignum* big = c_as<Bignum>(env->get_object(obj));
    double d = big->to_double(env->state());
    if(std::isinf(d)) {
      rb_warn("Bignum out of Float range");
      d = HUGE_VAL;
    }
    return d;
  }
Exemple #10
0
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;
}
Exemple #11
0
  double rb_big2dbl(VALUE obj) {
    NativeMethodEnvironment* env = NativeMethodEnvironment::get();

    Bignum* big = c_as<Bignum>(env->get_object(obj));
    double d = big->to_double(env->state());
    if(isinf(d)) {
      rb_warn("Bignum out of Float range");
      if(big->mp_val()->sign == MP_NEG) {
        d = -HUGE_VAL;
      } else {
        d = HUGE_VAL;
      }
    }
    return d;
  }
Exemple #12
0
bool Test_InvalidCoin()
{
	Bignum coinValue;
	
	try {
		// Pick a random non-prime Bignum
		for (uint32_t i = 0; i < NON_PRIME_TESTS; i++) {
			coinValue = Bignum::randBignum(g_Params->coinCommitmentGroup.modulus);
			coinValue = coinValue * 2;
			if (!coinValue.isPrime()) break;
		}
				
		PublicCoin pubCoin(g_Params);
		if (pubCoin.validate()) {
			// A blank coin should not be valid!
			return false;
		}		
		
		PublicCoin pubCoin2(g_Params, coinValue, ZQ_LOVELACE);
		if (pubCoin2.validate()) {
			// A non-prime coin should not be valid!
			return false;
		}
		
		PublicCoin pubCoin3 = pubCoin2;
		if (pubCoin2.validate()) {
			// A copy of a non-prime coin should not be valid!
			return false;
		}
		
		// Serialize and deserialize the coin
		CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
		ss << pubCoin;
		PublicCoin pubCoin4(g_Params, ss);
		if (pubCoin4.validate()) {
			// A deserialized copy of a non-prime coin should not be valid!
			return false;
		}
		
	} catch (runtime_error &e) {
		cout << "Caught exception: " << e.what() << endl;
		return false;
	}
	
	return true;
}
Exemple #13
0
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)");
}
Exemple #14
0
  Bignum::Bignum(const Bignum & bn) {
    init();
    decimal_point = bn.decimal_point;
    bignum_len = bn.bignum_len;

    for (int i = bignum_len - bn.bignum_used_len(); i < bignum_len; i++) {
      bignum[i] = bn[i];
    }
  }
/** Verifies that a commitment c is accumulated in accumulator a
 */
bool AccumulatorProofOfKnowledge:: Verify(const Accumulator& a, const Bignum& valueOfCommitmentToCoin) const {
	Bignum sg = params->accumulatorPoKCommitmentGroup.g;
	Bignum sh = params->accumulatorPoKCommitmentGroup.h;

	Bignum g_n = params->accumulatorQRNCommitmentGroup.g;
	Bignum h_n = params->accumulatorQRNCommitmentGroup.h;

	//According to the proof, this hash should be of length k_prime bits.  It is currently greater than that, which should not be a problem, but we should check this.
	CHashWriter hasher(0,0);
	hasher << *params << sg << sh << g_n << h_n << valueOfCommitmentToCoin << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4;

	Bignum c = Bignum(hasher.GetHash()); //this hash should be of length k_prime bits

	Bignum st_1_prime = (valueOfCommitmentToCoin.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * sg.pow_mod(s_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
	Bignum st_2_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * ((valueOfCommitmentToCoin * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(s_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(s_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
	Bignum st_3_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * (sg * valueOfCommitmentToCoin).pow_mod(s_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;

	Bignum t_1_prime = (C_r.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_zeta, params->accumulatorModulus) * g_n.pow_mod(s_epsilon, params->accumulatorModulus)) % params->accumulatorModulus;
	Bignum t_2_prime = (C_e.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_eta, params->accumulatorModulus) * g_n.pow_mod(s_alpha, params->accumulatorModulus)) % params->accumulatorModulus;
	Bignum t_3_prime = ((a.getValue()).pow_mod(c, params->accumulatorModulus) * C_u.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus;
	Bignum t_4_prime = (C_r.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus;

	bool result = false;

	bool result_st1 = (st_1 == st_1_prime);
	bool result_st2 = (st_2 == st_2_prime);
	bool result_st3 = (st_3 == st_3_prime);

	bool result_t1 = (t_1 == t_1_prime);
	bool result_t2 = (t_2 == t_2_prime);
	bool result_t3 = (t_3 == t_3_prime);
	bool result_t4 = (t_4 == t_4_prime);

	bool result_range = ((s_alpha >= -(params->maxCoinValue * Bignum(2).pow(params->k_prime + params->k_dprime + 1))) && (s_alpha <= (params->maxCoinValue * Bignum(2).pow(params->k_prime + params->k_dprime + 1))));

	result = result_st1 && result_st2 && result_st3 && result_t1 && result_t2 && result_t3 && result_t4 && result_range;

	return result;
}
Exemple #16
0
  /////////////////////////////////////
  //
  //  Operator Computing
  //
  ////////////////////////////////////
  Bignum Bignum::operator+(const Bignum & bn) const {
    Bignum tmp;
    const Bignum & self = *this;
    Bignum::Info info = Bignum::Info(self, bn);

    if (bn[info.b_index] < 0) {
      tmp = bn;
      tmp[info.b_index] = llabs(tmp[info.b_index]);
      return self - bn;
    } else if (self[info.a_index] < 0) {
      tmp = self;
      tmp[info.a_index] = llabs(tmp[info.a_index]);

      return bn - tmp;
    }

    for (int i = bignum_len - 1; i >= 0; i--) {
      tmp[i] += self[i] + bn[i];
      tmp.carry(i);
    }

    return tmp;
  }
Exemple #17
0
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;
}
Exemple #18
0
int main(int argc, char **argv)
{
    static Bignum resultModulus(0);
    uint32_t numBits = DEFAULT_MODULUS_SIZE;
    ofstream outfile;
    char* outfileName;
    bool writeToFile = false;
    
	while ((argc > 1) && (argv[1][0] == '-'))
	{
		switch (argv[1][1])
		{
			case 'b':
                numBits = atoi(argv[2]);
                ++argv;
                --argc;
				break;
                
            case 'o':
                outfileName = argv[2];
                writeToFile = true;
                break;
                
            case 'h':
                usage();
                break;
                
			default:
				printf("Wrong Argument: %s\n", argv[1]);
				usage();
                break;
		}
        
		++argv;
		--argc;
	}
    
    if (numBits < MIN_MODULUS_SIZE) {
        cout << "Modulus is below minimum length (" << MIN_MODULUS_SIZE << ") bits" << endl;
        return(0);
    }
    
    PrintWarning();
    
    cout << "Modulus size set to " << numBits << " bits." << endl;
    cout << "Generating parameters. This may take a few minutes..." << endl;
    
    // Generate two safe primes "p" and "q"
    Bignum *p, *q;
    p = new Bignum(0);
    q = new Bignum(0);
    *p = Bignum::generatePrime(numBits / 2, true);
    *q = Bignum::generatePrime(numBits / 2, true);
    
    // Multiply to compute N
    resultModulus = (*p) * (*q);
    
    // Wipe out the factors
    delete p;
    delete q;
    
    // Convert to a hexidecimal string
    std::string resultHex = resultModulus.ToString(16);
    
    cout << endl << "N = " << endl << resultHex << endl;
    
    if (writeToFile) {
        try {
            outfile.open (outfileName);
            outfile << resultHex;
            outfile.close();
            cout << endl << "Result has been written to file '" << outfileName << "'." << endl;
        } catch (std::runtime_error &e) {
            cout << "Unable to write to file:" << e.what() << endl;
        }
    }
}
Exemple #19
0
Value RandomState::random(Value arg)
{
    if (fixnump(arg))
      {
        long n = xlong(arg);
        if (n > 0)
          {
            mpz_t limit;
            mpz_init_set_si(limit, n);
            mpz_t result;
            mpz_init(result);
            mpz_urandomm(result, _state, limit);
            return normalize(result);
          }
      }
    else if (bignump(arg))
      {
        Bignum * b = the_bignum(arg);
        if (b->plusp())
          {
            mpz_t result;
            mpz_init(result);
            mpz_urandomm(result, _state, b->_z);
            return normalize(result);
          }
      }
    else if (single_float_p(arg))
      {
        float f = the_single_float(arg)->_f;
        if (f > 0)
          {
            mpz_t fixnum_limit;
            mpz_init_set_si(fixnum_limit, MOST_POSITIVE_FIXNUM);
            mpz_t fixnum_result;
            mpz_init(fixnum_result);
            mpz_urandomm(fixnum_result, _state, fixnum_limit);
            double double_result = mpz_get_si(fixnum_result);
            double_result /= MOST_POSITIVE_FIXNUM;
            return make_value(new SingleFloat(double_result * f));
          }
      }
    else if (double_float_p(arg))
      {
        double d = the_double_float(arg)->_d;
        if (d > 0)
          {
            mpz_t fixnum_limit;
            mpz_init_set_si(fixnum_limit, MOST_POSITIVE_FIXNUM);
            mpz_t fixnum_result;
            mpz_init(fixnum_result);
            mpz_urandomm(fixnum_result, _state, fixnum_limit);
            double double_result = mpz_get_si(fixnum_result);
            double_result /= MOST_POSITIVE_FIXNUM;
            return make_value(new DoubleFloat(double_result * d));
          }
      }
    return signal_type_error(arg,
                             list3(S_or,
                                   list2(S_integer, list1(FIXNUM_ZERO)),
                                   list2(S_float, list1(FIXNUM_ZERO))));
}
Exemple #20
0
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");
}
AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p,
        const Commitment& commitmentToCoin, const AccumulatorWitness& witness,
        Accumulator& a): params(p) {

	Bignum sg = params->accumulatorPoKCommitmentGroup.g;
	Bignum sh = params->accumulatorPoKCommitmentGroup.h;

	Bignum g_n = params->accumulatorQRNCommitmentGroup.g;
	Bignum h_n = params->accumulatorQRNCommitmentGroup.h;

	Bignum e = commitmentToCoin.getContents();
	Bignum r = commitmentToCoin.getRandomness();

	Bignum r_1 = Bignum::randBignum(params->accumulatorModulus/4);
	Bignum r_2 = Bignum::randBignum(params->accumulatorModulus/4);
	Bignum r_3 = Bignum::randBignum(params->accumulatorModulus/4);

	this->C_e = g_n.pow_mod(e, params->accumulatorModulus) * h_n.pow_mod(r_1, params->accumulatorModulus);
	this->C_u = witness.getValue() * h_n.pow_mod(r_2, params->accumulatorModulus);
	this->C_r = g_n.pow_mod(r_2, params->accumulatorModulus) * h_n.pow_mod(r_3, params->accumulatorModulus);

	Bignum r_alpha = Bignum::randBignum(params->maxCoinValue * Bignum(2).pow(params->k_prime + params->k_dprime));
	if(!(Bignum::randBignum(Bignum(3)) % 2)) {
		r_alpha = 0-r_alpha;
	}

	Bignum r_gamma = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
	Bignum r_phi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
	Bignum r_psi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
	Bignum r_sigma = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
	Bignum r_xi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);

	Bignum r_epsilon =  Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime));
	if(!(Bignum::randBignum(Bignum(3)) % 2)) {
		r_epsilon = 0-r_epsilon;
	}
	Bignum r_eta = Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime));
	if(!(Bignum::randBignum(Bignum(3)) % 2)) {
		r_eta = 0-r_eta;
	}
	Bignum r_zeta = Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime));
	if(!(Bignum::randBignum(Bignum(3)) % 2)) {
		r_zeta = 0-r_zeta;
	}

	Bignum r_beta = Bignum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * Bignum(2).pow(params->k_prime + params->k_dprime));
	if(!(Bignum::randBignum(Bignum(3)) % 2)) {
		r_beta = 0-r_beta;
	}
	Bignum r_delta = Bignum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * Bignum(2).pow(params->k_prime + params->k_dprime));
	if(!(Bignum::randBignum(Bignum(3)) % 2)) {
		r_delta = 0-r_delta;
	}

	this->st_1 = (sg.pow_mod(r_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
	this->st_2 = (((commitmentToCoin.getCommitmentValue() * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(r_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(r_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
	this->st_3 = ((sg * commitmentToCoin.getCommitmentValue()).pow_mod(r_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;

	this->t_1 = (h_n.pow_mod(r_zeta, params->accumulatorModulus) * g_n.pow_mod(r_epsilon, params->accumulatorModulus)) % params->accumulatorModulus;
	this->t_2 = (h_n.pow_mod(r_eta, params->accumulatorModulus) * g_n.pow_mod(r_alpha, params->accumulatorModulus)) % params->accumulatorModulus;
	this->t_3 = (C_u.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus;
	this->t_4 = (C_r.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus;

	CHashWriter hasher(0,0);
	hasher << *params << sg << sh << g_n << h_n << commitmentToCoin.getCommitmentValue() << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4;

	//According to the proof, this hash should be of length k_prime bits.  It is currently greater than that, which should not be a problem, but we should check this.
	Bignum c = Bignum(hasher.GetHash());

	this->s_alpha = r_alpha - c*e;
	this->s_beta = r_beta - c*r_2*e;
	this->s_zeta = r_zeta - c*r_3;
	this->s_sigma = r_sigma - c*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder));
	this->s_eta = r_eta - c*r_1;
	this->s_epsilon = r_epsilon - c*r_2;
	this->s_delta = r_delta - c*r_3*e;
	this->s_xi = r_xi + c*r*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder));
	this->s_phi = (r_phi - c*r) % params->accumulatorPoKCommitmentGroup.groupOrder;
	this->s_gamma = r_gamma - c*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder));
	this->s_psi = r_psi + c*r*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder));
}
Exemple #22
0
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)");
}
Exemple #23
0
bool
ZerocoinTutorial()
{
	// The following simple code illustrates the call flow for Zerocoin
	// applications. In a real currency network these operations would
	// be split between individual payers/payees, network nodes and miners.
	//
	// For each call we specify the participant who would use it.

	// Zerocoin uses exceptions (based on the runtime_error class)
	// to indicate all sorts of problems. Always remember to catch them!

	try {

		/********************************************************************/
		// What is it:      Parameter loading
		// Who does it:     ALL ZEROCOIN PARTICIPANTS
		// What it does:    Loads a trusted Zerocoin modulus "N" and
		//                  generates all associated parameters from it.
		//                  We use a hardcoded "N" that we generated using
		//                  the included 'paramgen' utility.
		/********************************************************************/

		// Load a test modulus from our hardcoded string (above)
		Bignum testModulus;
		testModulus.SetHex(std::string(TUTORIAL_TEST_MODULUS));

		// Set up the Zerocoin Params object
		libzerocoin::Params* params = new libzerocoin::Params(testModulus);

		cout << "Successfully loaded parameters." << endl;

		/********************************************************************/
		// What is it:      Coin generation
		// Who does it:     ZEROCOIN CLIENTS
		// What it does:    Generates a new 'zerocoin' coin using the
		//                  public parameters. Once generated, the client
		//                  will transmit the public portion of this coin
		//                  in a ZEROCOIN_MINT transaction. The inputs
		//                  to this transaction must add up to the zerocoin
		//                  denomination plus any transaction fees.
		/********************************************************************/

		// The following constructor does all the work of minting a brand
		// new zerocoin. It stores all the private values inside the
		// PrivateCoin object. This includes the coin secrets, which must be
		// stored in a secure location (wallet) at the client.
		libzerocoin::PrivateCoin newCoin(params);

		// Get a copy of the 'public' portion of the coin. You should
		// embed this into a Zerocoin 'MINT' transaction along with a series
		// of currency inputs totaling the assigned value of one zerocoin.
		libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin();

		cout << "Successfully minted a zerocoin." << endl;

		// Serialize the public coin to a CDataStream object.
		CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION);
		serializedCoin << pubCoin;

		/********************************************************************/
		// What is it:      Coin verification
		// Who does it:     TRANSACTION VERIFIERS
		// What it does:    Verifies the structure of a zerocoin obtained from
		//                  a ZEROCOIN_MINT transaction. All coins must be
		//                  verified before you operate on them.
		//                  Note that this is only part of the transaction
		//                  verification process! The client must also check
		//                  that (1) the inputs to the transaction are valid
		//                  and add up to the value of one zerocoin, (2) that
		//                  this particular zerocoin has not been minted before.
		/********************************************************************/

		// Deserialize the public coin into a fresh object. This will
		// automatically validate that the coin is correctly structured and
		// will throw an exception if it isn't. (You need to handle those.)
		libzerocoin::PublicCoin pubCoinNew(params, serializedCoin);

		cout << "Deserialized and verified the coin." << endl;

		/********************************************************************/
		// What is it:      Accumulator computation
		// Who does it:     ZEROCOIN CLIENTS & TRANSACTION VERIFIERS
		// What it does:    Collects a number of PublicCoin values drawn from
		//                  the block chain and calculates an accumulator.
		//                  This accumulator is incrementally computable;
		//                  you can stop and serialize it at any point
		//                  then continue accumulating new transactions.
		//                  The accumulator is also order-independent, so
		//                  the same coins can be accumulated in any order
		//                  to give the same result.
		//                  WARNING: do not accumulate the same coin twice!
		/********************************************************************/

		// Create an empty accumulator object
		libzerocoin::Accumulator accumulator(params);

		// Add several coins to it (we'll generate them here on the fly).
		for (uint32_t i = 0; i < COINS_TO_ACCUMULATE; i++) {
			libzerocoin::PrivateCoin testCoin(params);
			accumulator += testCoin.getPublicCoin();
		}

		// Serialize the accumulator object.
		//
		// If you're using Accumulator Checkpoints, each miner would
		// start by deserializing the accumulator checkpoint from the
		// previous block (or creating a new Accumulator if no previous
		// block exists). It will then add all the coins in the new block,
		// then serialize the resulting Accumulator object to obtain the
		// new checkpoint. All block verifiers should do the same thing
		// to check their work.
		CDataStream serializedAccumulator(SER_NETWORK, PROTOCOL_VERSION);
		serializedAccumulator << accumulator;

		// Deserialize the accumulator object
		libzerocoin::Accumulator newAccumulator(params, serializedAccumulator);

		// We can now continue accumulating things into the accumulator
		// we just deserialized. For example, let's put in the coin
		// we generated up above.
		newAccumulator += pubCoinNew;

		cout << "Successfully accumulated coins." << endl;

		/********************************************************************/
		// What is it:      Coin spend
		// Who does it:     ZEROCOIN CLIENTS
		// What it does:    Create a new transaction that spends a Zerocoin.
		//                  The user first authors a transaction specifying
		//                  a set of destination addresses (outputs). They
		//                  next compute an Accumulator over all coins in the
		//                  block chain (see above) and a Witness based on the
		//                  coin to be spent. Finally they instantiate a CoinSpend
		//                  object that 'signs' the transaction with a special
		//                  zero knowledge signature of knowledge over the coin
		//                  data, Witness and Accumulator.
		/********************************************************************/

		// We are going to spend the coin "newCoin" that we generated at the
		// top of this function.
		//
		// We'll use the accumulator we constructed above. This contains
		// a set of coins, but does NOT include the coin "newCoin".
		//
		// To generate the witness, we start with this accumulator and
		// add the public half of the coin we want to spend.
		libzerocoin::AccumulatorWitness witness(params, accumulator, newCoin.getPublicCoin());

		// Add the public half of "newCoin" to the Accumulator itself.
		accumulator += newCoin.getPublicCoin();

		// At this point we should generate a ZEROCOIN_SPEND transaction to
		// send to the network. This network should include a set of outputs
		// totalling to the value of one zerocoin (minus transaction fees).
		//
		// The format of this transaction is up to the implementer. Here we'll
		// assume you've formatted this transaction and placed the hash into
		// "transactionHash". We'll also assume "accumulatorHash" contains the
		// hash of the last block whose transactions are in the accumulator.
		uint256 transactionHash = DUMMY_TRANSACTION_HASH;
		uint256 accumulatorID = DUMMY_ACCUMULATOR_ID;

		// Place "transactionHash" and "accumulatorBlockHash" into a new
		// SpendMetaData object.
		libzerocoin::SpendMetaData metaData(accumulatorID, transactionHash);

		// Construct the CoinSpend object. This acts like a signature on the
		// transaction.
		libzerocoin::CoinSpend spend(params, newCoin, accumulator, witness, metaData);

		// This is a sanity check. The CoinSpend object should always verify,
		// but why not check before we put it onto the wire?
		if (!spend.Verify(accumulator, metaData)) {
			cout << "ERROR: Our new CoinSpend transaction did not verify!" << endl;
			return false;
		}
		
		// Serialize the CoinSpend object into a buffer.
		CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION);
		serializedCoinSpend << spend;
		
		cout << "Successfully generated a coin spend transaction." << endl;

		/********************************************************************/
		// What is it:      Coin spend verification
		// Who does it:     ALL PARTIES
		// What it does:    Verifies that a CoinSpend signature is correct
		//                  with respect to a ZEROCOIN_SPEND transaction hash.
		//                  The client must also extract the serial number from
		//                  the CoinSpend and verify that this serial number has
		//                  not previously appeared in another ZEROCOIN_SPEND
		//                  transaction.
		/********************************************************************/

		// Deserialize the CoinSpend intro a fresh object
		libzerocoin::CoinSpend newSpend(params, serializedCoinSpend);

		// Create a new metadata object to contain the hash of the received
		// ZEROCOIN_SPEND transaction. If we were a real client we'd actually
		// compute the hash of the received transaction here.
		libzerocoin::SpendMetaData newMetadata(accumulatorID, transactionHash);
		
		// If we were a real client we would now re-compute the Accumulator
		// from the information given in the ZEROCOIN_SPEND transaction.
		// For our purposes we'll just use the one we calculated above.
		//
		// Verify that the spend is valid with respect to the Accumulator
		// and the Metadata
		if (!newSpend.Verify(accumulator, newMetadata)) {
			cout << "ERROR: The CoinSpend transaction did not verify!" << endl;
			return false;
		}

		// Pull the serial number out of the CoinSpend object. If we
		// were a real Zerocoin client we would now check that the serial number
		// has not been spent before (in another ZEROCOIN_SPEND) transaction.
		// The serial number is stored as a Bignum.
		Bignum serialNumber = newSpend.getCoinSerialNumber();

		cout << "Successfully verified a coin spend transaction." << endl;
		cout << endl << "Coin serial number is:" << endl << serialNumber << endl;

		// We're done
		return true;

	} catch (runtime_error &e) {
		cout << e.what() << endl;
		return false;
	}

	return false;
}