forked from Zerocoin/libzerocoin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCoin.cpp
167 lines (136 loc) · 5.82 KB
/
Coin.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/**
* @file Coin.cpp
*
* @brief PublicCoin and PrivateCoin classes for the Zerocoin library.
*
* @author Ian Miers, Christina Garman and Matthew Green
* @date June 2013
*
* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green
* @license This project is released under the MIT license.
**/
#include <stdexcept>
#include "Zerocoin.h"
namespace libzerocoin {
//PublicCoin class
PublicCoin::PublicCoin(const Params* p):
params(p), denomination(ZQ_LOVELACE) {
if(this->params->initialized == false) {
throw std::invalid_argument("Params are not initialized");
}
};
PublicCoin::PublicCoin(const Params* p, const Bignum& coin, const CoinDenomination d):
params(p), value(coin), denomination(d) {
if(this->params->initialized == false) {
throw std::invalid_argument("Params are not initialized");
}
};
bool PublicCoin::operator==(const PublicCoin& rhs) const {
return this->value == rhs.value;// FIXME check param equality
}
bool PublicCoin::operator!=(const PublicCoin& rhs) const {
return !(*this == rhs);
}
const Bignum& PublicCoin::getValue() const {
return this->value;
}
const CoinDenomination PublicCoin::getDenomination() const {
return static_cast<CoinDenomination>(this->denomination);
}
bool PublicCoin::validate() const {
return (this->params->accumulatorParams.minCoinValue < value) && (value < this->params->accumulatorParams.maxCoinValue) && value.isPrime(params->zkp_iterations);
}
//PrivateCoin class
PrivateCoin::PrivateCoin(const Params* p, const CoinDenomination denomination): params(p), publicCoin(p) {
// Verify that the parameters are valid
if(this->params->initialized == false) {
throw std::invalid_argument("Params are not initialized");
}
#ifdef ZEROCOIN_FAST_MINT
// Mint a new coin with a random serial number using the fast process.
// This is more vulnerable to timing attacks so don't mint coins when
// somebody could be timing you.
this->mintCoinFast(denomination);
#else
// Mint a new coin with a random serial number using the standard process.
this->mintCoin(denomination);
#endif
}
/**
*
* @return the coins serial number
*/
const Bignum& PrivateCoin::getSerialNumber() const {
return this->serialNumber;
}
const Bignum& PrivateCoin::getRandomness() const {
return this->randomness;
}
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(¶ms->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)");
}
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)");
}
const PublicCoin& PrivateCoin::getPublicCoin() const {
return this->publicCoin;
}
} /* namespace libzerocoin */