CoinSpend.cpp 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // ECOin - Copyright (c) - 2014/2022 - GPLv3 - epsylon@riseup.net (https://03c8.net)
  2. #include "Zerocoin.h"
  3. namespace libzerocoin {
  4. CoinSpend::CoinSpend(const Params* p, const PrivateCoin& coin,
  5. Accumulator& a, const AccumulatorWitness& witness, const SpendMetaData& m):
  6. params(p),
  7. denomination(coin.getPublicCoin().getDenomination()),
  8. coinSerialNumber((coin.getSerialNumber())),
  9. accumulatorPoK(&p->accumulatorParams),
  10. serialNumberSoK(p),
  11. commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup) {
  12. // Sanity check: let's verify that the Witness is valid with respect to
  13. // the coin and Accumulator provided.
  14. if (!(witness.VerifyWitness(a, coin.getPublicCoin()))) {
  15. throw std::invalid_argument("Accumulator witness does not verify");
  16. }
  17. // 1: Generate two separate commitments to the public coin (C), each under
  18. // a different set of public parameters. We do this because the RSA accumulator
  19. // has specific requirements for the commitment parameters that are not
  20. // compatible with the group we use for the serial number proof.
  21. // Specifically, our serial number proof requires the order of the commitment group
  22. // to be the same as the modulus of the upper group. The Accumulator proof requires a
  23. // group with a significantly larger order.
  24. const Commitment fullCommitmentToCoinUnderSerialParams(&p->serialNumberSoKCommitmentGroup, coin.getPublicCoin().getValue());
  25. this->serialCommitmentToCoinValue = fullCommitmentToCoinUnderSerialParams.getCommitmentValue();
  26. const Commitment fullCommitmentToCoinUnderAccParams(&p->accumulatorParams.accumulatorPoKCommitmentGroup, coin.getPublicCoin().getValue());
  27. this->accCommitmentToCoinValue = fullCommitmentToCoinUnderAccParams.getCommitmentValue();
  28. // 2. Generate a ZK proof that the two commitments contain the same public coin.
  29. this->commitmentPoK = CommitmentProofOfKnowledge(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup, fullCommitmentToCoinUnderSerialParams, fullCommitmentToCoinUnderAccParams);
  30. // Now generate the two core ZK proofs:
  31. // 3. Proves that the committed public coin is in the Accumulator (PoK of "witness")
  32. this->accumulatorPoK = AccumulatorProofOfKnowledge(&p->accumulatorParams, fullCommitmentToCoinUnderAccParams, witness, a);
  33. // 4. Proves that the coin is correct w.r.t. serial number and hidden coin secret
  34. // (This proof is bound to the coin 'metadata', i.e., transaction hash)
  35. this->serialNumberSoK = SerialNumberSignatureOfKnowledge(p, coin, fullCommitmentToCoinUnderSerialParams, signatureHash(m));
  36. }
  37. const CBigNum&
  38. CoinSpend::getCoinSerialNumber() {
  39. return this->coinSerialNumber;
  40. }
  41. const CoinDenomination
  42. CoinSpend::getDenomination() {
  43. return static_cast<CoinDenomination>(this->denomination);
  44. }
  45. bool
  46. CoinSpend::Verify(const Accumulator& a, const SpendMetaData &m) const {
  47. // Verify both of the sub-proofs using the given meta-data
  48. return (a.getDenomination() == this->denomination)
  49. && commitmentPoK.Verify(serialCommitmentToCoinValue, accCommitmentToCoinValue)
  50. && accumulatorPoK.Verify(a, accCommitmentToCoinValue)
  51. && serialNumberSoK.Verify(coinSerialNumber, serialCommitmentToCoinValue, signatureHash(m));
  52. }
  53. const uint256 CoinSpend::signatureHash(const SpendMetaData &m) const {
  54. CHashWriter h(0,0);
  55. h << m << serialCommitmentToCoinValue << accCommitmentToCoinValue << commitmentPoK << accumulatorPoK;
  56. return h.GetHash();
  57. }
  58. } /* namespace libzerocoin */