4 * @brief CoinSpend class for the Zerocoin library.
6 * @author Ian Miers, Christina Garman and Matthew Green
9 * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green
10 * @license This project is released under the MIT license.
15 namespace libzerocoin {
17 CoinSpend::CoinSpend(const Params* p, const PrivateCoin& coin,
18 Accumulator& a, const AccumulatorWitness& witness, const SpendMetaData& m):
20 denomination(coin.getPublicCoin().getDenomination()),
21 coinSerialNumber((coin.getSerialNumber())),
22 accumulatorPoK(&p->accumulatorParams),
24 commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup) {
26 // Sanity check: let's verify that the Witness is valid with respect to
27 // the coin and Accumulator provided.
28 if (!(witness.VerifyWitness(a, coin.getPublicCoin()))) {
29 throw std::invalid_argument("Accumulator witness does not verify");
32 // 1: Generate two separate commitments to the public coin (C), each under
33 // a different set of public parameters. We do this because the RSA accumulator
34 // has specific requirements for the commitment parameters that are not
35 // compatible with the group we use for the serial number proof.
36 // Specifically, our serial number proof requires the order of the commitment group
37 // to be the same as the modulus of the upper group. The Accumulator proof requires a
38 // group with a significantly larger order.
39 const Commitment fullCommitmentToCoinUnderSerialParams(&p->serialNumberSoKCommitmentGroup, coin.getPublicCoin().getValue());
40 this->serialCommitmentToCoinValue = fullCommitmentToCoinUnderSerialParams.getCommitmentValue();
42 const Commitment fullCommitmentToCoinUnderAccParams(&p->accumulatorParams.accumulatorPoKCommitmentGroup, coin.getPublicCoin().getValue());
43 this->accCommitmentToCoinValue = fullCommitmentToCoinUnderAccParams.getCommitmentValue();
45 // 2. Generate a ZK proof that the two commitments contain the same public coin.
46 this->commitmentPoK = CommitmentProofOfKnowledge(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup, fullCommitmentToCoinUnderSerialParams, fullCommitmentToCoinUnderAccParams);
48 // Now generate the two core ZK proofs:
49 // 3. Proves that the committed public coin is in the Accumulator (PoK of "witness")
50 this->accumulatorPoK = AccumulatorProofOfKnowledge(&p->accumulatorParams, fullCommitmentToCoinUnderAccParams, witness, a);
52 // 4. Proves that the coin is correct w.r.t. serial number and hidden coin secret
53 // (This proof is bound to the coin 'metadata', i.e., transaction hash)
54 this->serialNumberSoK = SerialNumberSignatureOfKnowledge(p, coin, fullCommitmentToCoinUnderSerialParams, signatureHash(m));
58 CoinSpend::getCoinSerialNumber() {
59 return this->coinSerialNumber;
62 const CoinDenomination
63 CoinSpend::getDenomination() {
64 return static_cast<CoinDenomination>(this->denomination);
68 CoinSpend::Verify(const Accumulator& a, const SpendMetaData &m) const {
69 // Verify both of the sub-proofs using the given meta-data
70 return (a.getDenomination() == this->denomination)
71 && commitmentPoK.Verify(serialCommitmentToCoinValue, accCommitmentToCoinValue)
72 && accumulatorPoK.Verify(a, accCommitmentToCoinValue)
73 && serialNumberSoK.Verify(coinSerialNumber, serialCommitmentToCoinValue, signatureHash(m));
76 const uint256 CoinSpend::signatureHash(const SpendMetaData &m) const {
78 h << m << serialCommitmentToCoinValue << accCommitmentToCoinValue << commitmentPoK << accumulatorPoK;
82 } /* namespace libzerocoin */