12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- // ECOin - Copyright (c) - 2014/2022 - GPLv3 - epsylon@riseup.net (https://03c8.net)
- #include "Zerocoin.h"
- namespace libzerocoin {
- CoinSpend::CoinSpend(const Params* p, const PrivateCoin& coin,
- Accumulator& a, const AccumulatorWitness& witness, const SpendMetaData& m):
- params(p),
- denomination(coin.getPublicCoin().getDenomination()),
- coinSerialNumber((coin.getSerialNumber())),
- accumulatorPoK(&p->accumulatorParams),
- serialNumberSoK(p),
- commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup) {
- // Sanity check: let's verify that the Witness is valid with respect to
- // the coin and Accumulator provided.
- if (!(witness.VerifyWitness(a, coin.getPublicCoin()))) {
- throw std::invalid_argument("Accumulator witness does not verify");
- }
- // 1: Generate two separate commitments to the public coin (C), each under
- // a different set of public parameters. We do this because the RSA accumulator
- // has specific requirements for the commitment parameters that are not
- // compatible with the group we use for the serial number proof.
- // Specifically, our serial number proof requires the order of the commitment group
- // to be the same as the modulus of the upper group. The Accumulator proof requires a
- // group with a significantly larger order.
- const Commitment fullCommitmentToCoinUnderSerialParams(&p->serialNumberSoKCommitmentGroup, coin.getPublicCoin().getValue());
- this->serialCommitmentToCoinValue = fullCommitmentToCoinUnderSerialParams.getCommitmentValue();
- const Commitment fullCommitmentToCoinUnderAccParams(&p->accumulatorParams.accumulatorPoKCommitmentGroup, coin.getPublicCoin().getValue());
- this->accCommitmentToCoinValue = fullCommitmentToCoinUnderAccParams.getCommitmentValue();
- // 2. Generate a ZK proof that the two commitments contain the same public coin.
- this->commitmentPoK = CommitmentProofOfKnowledge(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup, fullCommitmentToCoinUnderSerialParams, fullCommitmentToCoinUnderAccParams);
- // Now generate the two core ZK proofs:
- // 3. Proves that the committed public coin is in the Accumulator (PoK of "witness")
- this->accumulatorPoK = AccumulatorProofOfKnowledge(&p->accumulatorParams, fullCommitmentToCoinUnderAccParams, witness, a);
- // 4. Proves that the coin is correct w.r.t. serial number and hidden coin secret
- // (This proof is bound to the coin 'metadata', i.e., transaction hash)
- this->serialNumberSoK = SerialNumberSignatureOfKnowledge(p, coin, fullCommitmentToCoinUnderSerialParams, signatureHash(m));
- }
- const CBigNum&
- CoinSpend::getCoinSerialNumber() {
- return this->coinSerialNumber;
- }
- const CoinDenomination
- CoinSpend::getDenomination() {
- return static_cast<CoinDenomination>(this->denomination);
- }
- bool
- CoinSpend::Verify(const Accumulator& a, const SpendMetaData &m) const {
- // Verify both of the sub-proofs using the given meta-data
- return (a.getDenomination() == this->denomination)
- && commitmentPoK.Verify(serialCommitmentToCoinValue, accCommitmentToCoinValue)
- && accumulatorPoK.Verify(a, accCommitmentToCoinValue)
- && serialNumberSoK.Verify(coinSerialNumber, serialCommitmentToCoinValue, signatureHash(m));
- }
- const uint256 CoinSpend::signatureHash(const SpendMetaData &m) const {
- CHashWriter h(0,0);
- h << m << serialCommitmentToCoinValue << accCommitmentToCoinValue << commitmentPoK << accumulatorPoK;
- return h.GetHash();
- }
- } /* namespace libzerocoin */
|