CoinSpend::CoinSpend(const Params* p, const PrivateCoin& coin, Accumulator& a, const AccumulatorWitness& witness, const SpendMetaData& m): denomination(coin.getPublicCoin().getDenomination()), coinSerialNumber((coin.getSerialNumber())), accumulatorPoK(&p->accumulatorParams), serialNumberSoK(p), commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup), metadata(m) { // 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, are serial number proof requires the order of the commitment group // to be the same as the modulus of the upper group. 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()); }
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 ZerocoinException("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); cout << "GNOSIS DEBUG: commitmentPoK is " << this->commitmentPoK.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) << " bytes" << endl;; // 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); cout << "GNOSIS DEBUG: accPoK is " << this->accumulatorPoK.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) << " bytes" << endl;; // 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)); cout << "GNOSIS DEBUG: snSoK is " << this->serialNumberSoK.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) << " bytes" << endl;; }
void CzPIVWallet::GenerateMint(const uint32_t& nCount, const CoinDenomination denom, PrivateCoin& coin, CDeterministicMint& dMint) { uint512 seedZerocoin = GetZerocoinSeed(nCount); CBigNum bnValue; CBigNum bnSerial; CBigNum bnRandomness; CKey key; SeedToZPIV(seedZerocoin, bnValue, bnSerial, bnRandomness, key); coin = PrivateCoin(Params().Zerocoin_Params(false), denom, bnSerial, bnRandomness); coin.setPrivKey(key.GetPrivKey()); coin.setVersion(PrivateCoin::CURRENT_VERSION); uint256 hashSeed = Hash(seedMaster.begin(), seedMaster.end()); uint256 hashSerial = GetSerialHash(bnSerial); uint256 nSerial = bnSerial.getuint256(); uint256 hashStake = Hash(nSerial.begin(), nSerial.end()); uint256 hashPubcoin = GetPubCoinHash(bnValue); dMint = CDeterministicMint(coin.getVersion(), nCount, hashSeed, hashSerial, hashPubcoin, hashStake); dMint.SetDenomination(denom); }
SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const ZerocoinParams* p, const PrivateCoin& coin, const Commitment& commitmentToCoin, uint256 msghash):params(p), s_notprime(p->zkp_iterations), sprime(p->zkp_iterations) { // Sanity check: verify that the order of the "accumulatedValueCommitmentGroup" is // equal to the modulus of "coinCommitmentGroup". Otherwise we will produce invalid // proofs. if (params->coinCommitmentGroup.modulus != params->serialNumberSoKCommitmentGroup.groupOrder) { throw std::runtime_error("Groups are not structured correctly."); } CBigNum a = params->coinCommitmentGroup.g; CBigNum b = params->coinCommitmentGroup.h; CBigNum g = params->serialNumberSoKCommitmentGroup.g; CBigNum h = params->serialNumberSoKCommitmentGroup.h; CHashWriter hasher(0,0); hasher << *params << commitmentToCoin.getCommitmentValue() << coin.getSerialNumber() << msghash; vector<CBigNum> r(params->zkp_iterations); vector<CBigNum> v_seed(params->zkp_iterations); vector<CBigNum> v_expanded(params->zkp_iterations); vector<CBigNum> c(params->zkp_iterations); for(uint32_t i=0; i < params->zkp_iterations; i++) { r[i] = CBigNum::randBignum(params->coinCommitmentGroup.groupOrder); //use a random 256 bit seed that expands to 1024 bit for v[i] while (true) { uint256 hashRand = CBigNum::randBignum(CBigNum(~uint256(0))).getuint256(); CBigNum bnExpanded = SeedTo1024(hashRand); if(bnExpanded > params->serialNumberSoKCommitmentGroup.groupOrder) continue; v_seed[i] = CBigNum(hashRand); v_expanded[i] = bnExpanded; break; } } for(uint32_t i=0; i < params->zkp_iterations; i++) { // compute g^{ {a^x b^r} h^v} mod p2 c[i] = challengeCalculation(coin.getSerialNumber(), r[i], v_expanded[i]); } // We can't hash data in parallel either // because OPENMP cannot not guarantee loops // execute in order. for(uint32_t i=0; i < params->zkp_iterations; i++) { hasher << c[i]; } this->hash = hasher.GetHash(); unsigned char *hashbytes = (unsigned char*) &hash; for(uint32_t i = 0; i < params->zkp_iterations; i++) { int bit = i % 8; int byte = i / 8; bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01); if (challenge_bit) { s_notprime[i] = r[i]; sprime[i] = v_seed[i]; } else { s_notprime[i] = r[i] - coin.getRandomness(); sprime[i] = v_expanded[i] - (commitmentToCoin.getRandomness() * b.pow_mod(r[i] - coin.getRandomness(), params->serialNumberSoKCommitmentGroup.groupOrder)); } } }