Coin.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // ECOin - Copyright (c) - 2014/2022 - GPLv3 - epsylon@riseup.net (https://03c8.net)º
  2. #include <stdexcept>
  3. #include "Zerocoin.h"
  4. namespace libzerocoin {
  5. //PublicCoin class
  6. PublicCoin::PublicCoin(const Params* p):
  7. params(p), denomination(ZQ_PEDERSEN) {
  8. if(this->params->initialized == false) {
  9. throw std::invalid_argument("Params are not initialized");
  10. }
  11. };
  12. PublicCoin::PublicCoin(const Params* p, const CBigNum& coin, const CoinDenomination d):
  13. params(p), value(coin), denomination(d) {
  14. if(this->params->initialized == false) {
  15. throw std::invalid_argument("Params are not initialized");
  16. }
  17. };
  18. bool PublicCoin::operator==(const PublicCoin& rhs) const {
  19. return this->value == rhs.value;// FIXME check param equality
  20. }
  21. bool PublicCoin::operator!=(const PublicCoin& rhs) const {
  22. return !(*this == rhs);
  23. }
  24. const CBigNum& PublicCoin::getValue() const {
  25. return this->value;
  26. }
  27. const CoinDenomination PublicCoin::getDenomination() const {
  28. return static_cast<CoinDenomination>(this->denomination);
  29. }
  30. bool PublicCoin::validate() const {
  31. return (this->params->accumulatorParams.minCoinValue < value) && (value < this->params->accumulatorParams.maxCoinValue) && value.isPrime(params->zkp_iterations);
  32. }
  33. //PrivateCoin class
  34. PrivateCoin::PrivateCoin(const Params* p, const CoinDenomination denomination): params(p), publicCoin(p) {
  35. // Verify that the parameters are valid
  36. if(this->params->initialized == false) {
  37. throw std::invalid_argument("Params are not initialized");
  38. }
  39. #ifdef ZEROCOIN_FAST_MINT
  40. // Mint a new coin with a random serial number using the fast process.
  41. // This is more vulnerable to timing attacks so don't mint coins when
  42. // somebody could be timing you.
  43. this->mintCoinFast(denomination);
  44. #else
  45. // Mint a new coin with a random serial number using the standard process.
  46. this->mintCoin(denomination);
  47. #endif
  48. }
  49. /**
  50. *
  51. * @return the coins serial number
  52. */
  53. const CBigNum& PrivateCoin::getSerialNumber() const {
  54. return this->serialNumber;
  55. }
  56. const CBigNum& PrivateCoin::getRandomness() const {
  57. return this->randomness;
  58. }
  59. void PrivateCoin::mintCoin(const CoinDenomination denomination) {
  60. // Repeat this process up to MAX_COINMINT_ATTEMPTS times until
  61. // we obtain a prime number
  62. for(uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
  63. // Generate a random serial number in the range 0...{q-1} where
  64. // "q" is the order of the commitment group.
  65. CBigNum s = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder);
  66. // Generate a Pedersen commitment to the serial number "s"
  67. Commitment coin(&params->coinCommitmentGroup, s);
  68. // Now verify that the commitment is a prime number
  69. // in the appropriate range. If not, we'll throw this coin
  70. // away and generate a new one.
  71. if (coin.getCommitmentValue().isPrime(ZEROCOIN_MINT_PRIME_PARAM) &&
  72. coin.getCommitmentValue() >= params->accumulatorParams.minCoinValue &&
  73. coin.getCommitmentValue() <= params->accumulatorParams.maxCoinValue) {
  74. // Found a valid coin. Store it.
  75. this->serialNumber = s;
  76. this->randomness = coin.getRandomness();
  77. this->publicCoin = PublicCoin(params,coin.getCommitmentValue(), denomination);
  78. // Success! We're done.
  79. return;
  80. }
  81. }
  82. // We only get here if we did not find a coin within
  83. // MAX_COINMINT_ATTEMPTS. Throw an exception.
  84. throw ZerocoinException("Unable to mint a new Zerocoin (too many attempts)");
  85. }
  86. void PrivateCoin::mintCoinFast(const CoinDenomination denomination) {
  87. // Generate a random serial number in the range 0...{q-1} where
  88. // "q" is the order of the commitment group.
  89. CBigNum s = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder);
  90. // Generate a random number "r" in the range 0...{q-1}
  91. CBigNum r = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder);
  92. // Manually compute a Pedersen commitment to the serial number "s" under randomness "r"
  93. // C = g^s * h^r mod p
  94. CBigNum 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);
  95. // Repeat this process up to MAX_COINMINT_ATTEMPTS times until
  96. // we obtain a prime number
  97. for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
  98. // First verify that the commitment is a prime number
  99. // in the appropriate range. If not, we'll throw this coin
  100. // away and generate a new one.
  101. if (commitmentValue.isPrime(ZEROCOIN_MINT_PRIME_PARAM) &&
  102. commitmentValue >= params->accumulatorParams.minCoinValue &&
  103. commitmentValue <= params->accumulatorParams.maxCoinValue) {
  104. // Found a valid coin. Store it.
  105. this->serialNumber = s;
  106. this->randomness = r;
  107. this->publicCoin = PublicCoin(params, commitmentValue, denomination);
  108. // Success! We're done.
  109. return;
  110. }
  111. // Generate a new random "r_delta" in 0...{q-1}
  112. CBigNum r_delta = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder);
  113. // The commitment was not prime. Increment "r" and recalculate "C":
  114. // r = r + r_delta mod q
  115. // C = C * h mod p
  116. r = (r + r_delta) % this->params->coinCommitmentGroup.groupOrder;
  117. commitmentValue = commitmentValue.mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r_delta, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus);
  118. }
  119. // We only get here if we did not find a coin within
  120. // MAX_COINMINT_ATTEMPTS. Throw an exception.
  121. throw ZerocoinException("Unable to mint a new Zerocoin (too many attempts)");
  122. }
  123. const PublicCoin& PrivateCoin::getPublicCoin() const {
  124. return this->publicCoin;
  125. }
  126. } /* namespace libzerocoin */