4 * @brief PublicCoin and PrivateCoin classes for the Zerocoin library.
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.
16 namespace libzerocoin {
19 PublicCoin::PublicCoin(const Params* p):
20 params(p), denomination(ZQ_PEDERSEN) {
21 if(this->params->initialized == false) {
22 throw std::invalid_argument("Params are not initialized");
26 PublicCoin::PublicCoin(const Params* p, const Bignum& coin, const CoinDenomination d):
27 params(p), value(coin), denomination(d) {
28 if(this->params->initialized == false) {
29 throw std::invalid_argument("Params are not initialized");
33 bool PublicCoin::operator==(const PublicCoin& rhs) const {
34 return this->value == rhs.value;// FIXME check param equality
37 bool PublicCoin::operator!=(const PublicCoin& rhs) const {
38 return !(*this == rhs);
41 const Bignum& PublicCoin::getValue() const {
45 const CoinDenomination PublicCoin::getDenomination() const {
46 return static_cast<CoinDenomination>(this->denomination);
49 bool PublicCoin::validate() const {
50 return (this->params->accumulatorParams.minCoinValue < value) && (value < this->params->accumulatorParams.maxCoinValue) && value.isPrime(params->zkp_iterations);
54 PrivateCoin::PrivateCoin(const Params* p, const CoinDenomination denomination): params(p), publicCoin(p) {
55 // Verify that the parameters are valid
56 if(this->params->initialized == false) {
57 throw std::invalid_argument("Params are not initialized");
60 #ifdef ZEROCOIN_FAST_MINT
61 // Mint a new coin with a random serial number using the fast process.
62 // This is more vulnerable to timing attacks so don't mint coins when
63 // somebody could be timing you.
64 this->mintCoinFast(denomination);
66 // Mint a new coin with a random serial number using the standard process.
67 this->mintCoin(denomination);
74 * @return the coins serial number
76 const Bignum& PrivateCoin::getSerialNumber() const {
77 return this->serialNumber;
80 const Bignum& PrivateCoin::getRandomness() const {
81 return this->randomness;
84 void PrivateCoin::mintCoin(const CoinDenomination denomination) {
85 // Repeat this process up to MAX_COINMINT_ATTEMPTS times until
86 // we obtain a prime number
87 for(uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
89 // Generate a random serial number in the range 0...{q-1} where
90 // "q" is the order of the commitment group.
91 Bignum s = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
93 // Generate a Pedersen commitment to the serial number "s"
94 Commitment coin(¶ms->coinCommitmentGroup, s);
96 // Now verify that the commitment is a prime number
97 // in the appropriate range. If not, we'll throw this coin
98 // away and generate a new one.
99 if (coin.getCommitmentValue().isPrime(ZEROCOIN_MINT_PRIME_PARAM) &&
100 coin.getCommitmentValue() >= params->accumulatorParams.minCoinValue &&
101 coin.getCommitmentValue() <= params->accumulatorParams.maxCoinValue) {
102 // Found a valid coin. Store it.
103 this->serialNumber = s;
104 this->randomness = coin.getRandomness();
105 this->publicCoin = PublicCoin(params,coin.getCommitmentValue(), denomination);
107 // Success! We're done.
112 // We only get here if we did not find a coin within
113 // MAX_COINMINT_ATTEMPTS. Throw an exception.
114 throw ZerocoinException("Unable to mint a new Zerocoin (too many attempts)");
117 void PrivateCoin::mintCoinFast(const CoinDenomination denomination) {
119 // Generate a random serial number in the range 0...{q-1} where
120 // "q" is the order of the commitment group.
121 Bignum s = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
123 // Generate a random number "r" in the range 0...{q-1}
124 Bignum r = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
126 // Manually compute a Pedersen commitment to the serial number "s" under randomness "r"
127 // C = g^s * h^r mod p
128 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);
130 // Repeat this process up to MAX_COINMINT_ATTEMPTS times until
131 // we obtain a prime number
132 for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
133 // First verify that the commitment is a prime number
134 // in the appropriate range. If not, we'll throw this coin
135 // away and generate a new one.
136 if (commitmentValue.isPrime(ZEROCOIN_MINT_PRIME_PARAM) &&
137 commitmentValue >= params->accumulatorParams.minCoinValue &&
138 commitmentValue <= params->accumulatorParams.maxCoinValue) {
139 // Found a valid coin. Store it.
140 this->serialNumber = s;
141 this->randomness = r;
142 this->publicCoin = PublicCoin(params, commitmentValue, denomination);
144 // Success! We're done.
148 // Generate a new random "r_delta" in 0...{q-1}
149 Bignum r_delta = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
151 // The commitment was not prime. Increment "r" and recalculate "C":
152 // r = r + r_delta mod q
154 r = (r + r_delta) % this->params->coinCommitmentGroup.groupOrder;
155 commitmentValue = commitmentValue.mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r_delta, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus);
158 // We only get here if we did not find a coin within
159 // MAX_COINMINT_ATTEMPTS. Throw an exception.
160 throw ZerocoinException("Unable to mint a new Zerocoin (too many attempts)");
163 const PublicCoin& PrivateCoin::getPublicCoin() const {
164 return this->publicCoin;
167 } /* namespace libzerocoin */