Commitment.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // ECOin - Copyright (c) - 2014/2022 - GPLv3 - epsylon@riseup.net (https://03c8.net)
  2. #include <stdlib.h>
  3. #include "Zerocoin.h"
  4. namespace libzerocoin {
  5. //Commitment class
  6. Commitment::Commitment::Commitment(const IntegerGroupParams* p,
  7. const CBigNum& value): params(p), contents(value) {
  8. this->randomness = CBigNum::randBignum(params->groupOrder);
  9. this->commitmentValue = (params->g.pow_mod(this->contents, params->modulus).mul_mod(
  10. params->h.pow_mod(this->randomness, params->modulus), params->modulus));
  11. }
  12. const CBigNum& Commitment::getCommitmentValue() const {
  13. return this->commitmentValue;
  14. }
  15. const CBigNum& Commitment::getRandomness() const {
  16. return this->randomness;
  17. }
  18. const CBigNum& Commitment::getContents() const {
  19. return this->contents;
  20. }
  21. //CommitmentProofOfKnowledge class
  22. CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* ap, const IntegerGroupParams* bp): ap(ap), bp(bp) {}
  23. // TODO: get parameters from the commitment group
  24. CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* aParams,
  25. const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b):
  26. ap(aParams),bp(bParams)
  27. {
  28. CBigNum r1, r2, r3;
  29. // First: make sure that the two commitments have the
  30. // same contents.
  31. if (a.getContents() != b.getContents()) {
  32. throw std::invalid_argument("Both commitments must contain the same value");
  33. }
  34. // Select three random values "r1, r2, r3" in the range 0 to (2^l)-1 where l is:
  35. // length of challenge value + max(modulus 1, modulus 2, order 1, order 2) + margin.
  36. // We set "margin" to be a relatively generous security parameter.
  37. //
  38. // We choose these large values to ensure statistical zero knowledge.
  39. uint32_t randomSize = COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN +
  40. std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()),
  41. std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize()));
  42. CBigNum maxRange = (CBigNum(2).pow(randomSize) - CBigNum(1));
  43. r1 = CBigNum::randBignum(maxRange);
  44. r2 = CBigNum::randBignum(maxRange);
  45. r3 = CBigNum::randBignum(maxRange);
  46. // Generate two random, ephemeral commitments "T1, T2"
  47. // of the form:
  48. // T1 = g1^r1 * h1^r2 mod p1
  49. // T2 = g2^r1 * h2^r3 mod p2
  50. //
  51. // Where (g1, h1, p1) are from "aParams" and (g2, h2, p2) are from "bParams".
  52. CBigNum T1 = this->ap->g.pow_mod(r1, this->ap->modulus).mul_mod((this->ap->h.pow_mod(r2, this->ap->modulus)), this->ap->modulus);
  53. CBigNum T2 = this->bp->g.pow_mod(r1, this->bp->modulus).mul_mod((this->bp->h.pow_mod(r3, this->bp->modulus)), this->bp->modulus);
  54. // Now hash commitment "A" with commitment "B" as well as the
  55. // parameters and the two ephemeral commitments "T1, T2" we just generated
  56. this->challenge = calculateChallenge(a.getCommitmentValue(), b.getCommitmentValue(), T1, T2);
  57. // Let "m" be the contents of the commitments "A, B". We have:
  58. // A = g1^m * h1^x mod p1
  59. // B = g2^m * h2^y mod p2
  60. // T1 = g1^r1 * h1^r2 mod p1
  61. // T2 = g2^r1 * h2^r3 mod p2
  62. //
  63. // Now compute:
  64. // S1 = r1 + (m * challenge) -- note, not modular arithmetic
  65. // S2 = r2 + (x * challenge) -- note, not modular arithmetic
  66. // S3 = r3 + (y * challenge) -- note, not modular arithmetic
  67. this->S1 = r1 + (a.getContents() * this->challenge);
  68. this->S2 = r2 + (a.getRandomness() * this->challenge);
  69. this->S3 = r3 + (b.getRandomness() * this->challenge);
  70. // We're done. The proof is S1, S2, S3 and "challenge", all of which
  71. // are stored in member variables.
  72. }
  73. bool CommitmentProofOfKnowledge::Verify(const CBigNum& A, const CBigNum& B) const
  74. {
  75. // Compute the maximum range of S1, S2, S3 and verify that the given values are
  76. // in a correct range. This might be an unnecessary check.
  77. uint32_t maxSize = 64 * (COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN +
  78. std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()),
  79. std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize())));
  80. if ((uint32_t)this->S1.bitSize() > maxSize ||
  81. (uint32_t)this->S2.bitSize() > maxSize ||
  82. (uint32_t)this->S3.bitSize() > maxSize ||
  83. this->S1 < CBigNum(0) ||
  84. this->S2 < CBigNum(0) ||
  85. this->S3 < CBigNum(0) ||
  86. this->challenge < CBigNum(0) ||
  87. this->challenge > (CBigNum(2).pow(COMMITMENT_EQUALITY_CHALLENGE_SIZE) - CBigNum(1))) {
  88. // Invalid inputs. Reject.
  89. return false;
  90. }
  91. // Compute T1 = g1^S1 * h1^S2 * inverse(A^{challenge}) mod p1
  92. CBigNum T1 = A.pow_mod(this->challenge, ap->modulus).inverse(ap->modulus).mul_mod(
  93. (ap->g.pow_mod(S1, ap->modulus).mul_mod(ap->h.pow_mod(S2, ap->modulus), ap->modulus)),
  94. ap->modulus);
  95. // Compute T2 = g2^S1 * h2^S3 * inverse(B^{challenge}) mod p2
  96. CBigNum T2 = B.pow_mod(this->challenge, bp->modulus).inverse(bp->modulus).mul_mod(
  97. (bp->g.pow_mod(S1, bp->modulus).mul_mod(bp->h.pow_mod(S3, bp->modulus), bp->modulus)),
  98. bp->modulus);
  99. // Hash T1 and T2 along with all of the public parameters
  100. CBigNum computedChallenge = calculateChallenge(A, B, T1, T2);
  101. // Return success if the computed challenge matches the incoming challenge
  102. if(computedChallenge == this->challenge) {
  103. return true;
  104. }
  105. // Otherwise return failure
  106. return false;
  107. }
  108. const CBigNum CommitmentProofOfKnowledge::calculateChallenge(const CBigNum& a, const CBigNum& b, const CBigNum &commitOne, const CBigNum &commitTwo) const {
  109. CHashWriter hasher(0,0);
  110. // Hash together the following elements:
  111. // * A string identifying the proof
  112. // * Commitment A
  113. // * Commitment B
  114. // * Ephemeral commitment T1
  115. // * Ephemeral commitment T2
  116. // * A serialized instance of the commitment A parameters
  117. // * A serialized instance of the commitment B parameters
  118. hasher << std::string(ZEROCOIN_COMMITMENT_EQUALITY_PROOF);
  119. hasher << commitOne;
  120. hasher << std::string("||");
  121. hasher << commitTwo;
  122. hasher << std::string("||");
  123. hasher << a;
  124. hasher << std::string("||");
  125. hasher << b;
  126. hasher << std::string("||");
  127. hasher << *(this->ap);
  128. hasher << std::string("||");
  129. hasher << *(this->bp);
  130. // Convert the SHA256 result into a CBigNum
  131. // Note that if we ever change the size of the hash function we will have
  132. // to update COMMITMENT_EQUALITY_CHALLENGE_SIZE appropriately!
  133. return CBigNum(hasher.GetHash());
  134. }
  135. } /* namespace libzerocoin */