#include #include "client.hpp" extern const curvepoint_fp_t bn_curvegen; Curvepoint PrsonaClient::elGamalGenerator = Curvepoint(); bool PrsonaClient::malicious_server = false; bool PrsonaClient::malicious_client = false; mpz_class log2(mpz_class x) { mpz_class retval = 0; while (x > 0) { retval++; x = x >> 1; } return retval; } PrsonaClient::PrsonaClient(const BGNPublicKey& serverPublicKey, const Curvepoint& elGamalBlindGenerator) : serverPublicKey(serverPublicKey), elGamalBlindGenerator(elGamalBlindGenerator), max_checked(0) { elGamalGenerator = Curvepoint(bn_curvegen); longTermPrivateKey.set_random(); inversePrivateKey = longTermPrivateKey.curveInverse(); decryption_memoizer[elGamalBlindGenerator * max_checked] = max_checked; } void PrsonaClient::set_malicious_server() { malicious_server = true; } void PrsonaClient::set_malicious_client() { malicious_client = true; } Curvepoint PrsonaClient::get_short_term_public_key(Proof &pi) const { pi = generate_stpk_proof(); return currentFreshGenerator * longTermPrivateKey; } void PrsonaClient::make_votes(Proof& pi, std::vector& encryptedVotes, const std::vector& vote, const std::vector& replace) const { encryptedVotes.clear(); for (size_t i = 0; i < vote.size(); i++) { CurveBipoint currScore; if (replace[i]) serverPublicKey.encrypt(currScore, vote[i]); else currScore = serverPublicKey.rerandomize(currEncryptedVotes[i]); encryptedVotes.push_back(currScore); } pi = generate_vote_proof(encryptedVotes, vote); } void PrsonaClient::receive_fresh_generator(const Proof& pi, const Curvepoint& freshGenerator) { if (!verify_generator_proof(pi, freshGenerator)) { std::cerr << "Could not verify proof of valid fresh generator." << std::endl; return; } currentFreshGenerator = freshGenerator; } void PrsonaClient::receive_vote_tally(const Proof& pi, const EGCiphertext& score, bool isDefault, const Scalar& randomizationMask) { if (isDefault) { if (!verify_default_tally_proof(pi, score)) { std::cerr << "Could not verify proof of valid default tally." << std::endl; return; } } else { if (!verify_valid_tally_proof(pi, score)) { std::cerr << "Could not verify proof of valid tally." << std::endl; return; } } currentEncryptedScore = score; currentRandomizationMask = randomizationMask; decrypt_score(score); } void PrsonaClient::receive_encrypted_votes(const Proof& pi, const std::vector& votes, bool isDefault) { if (isDefault) { if (!verify_default_votes_proof(pi, votes)) { std::cerr << "Could not verify proof of valid default votes." << std::endl; return; } } else { if (!verify_valid_votes_proof(pi, votes)) { std::cerr << "Could not verify proof of valid votes." << std::endl; return; } } currEncryptedVotes = votes; } std::vector PrsonaClient::generate_reputation_proof(const Scalar& threshold) const { std::vector retval; if (threshold > currentScore) return retval; if (!malicious_client) { Proof currProof; currProof.basic = "PROOF"; retval.push_back(currProof); return retval; } // retval.push_back(generate_ownership_proof()); // mpz_class proofVal = currentScore.curveSub(threshold).toInt(); // mpz_class proofBits = log2(currEncryptedVotes.size() * 3 - threshold.toInt()); // std::vector masksPerBit; // masksPerBit.push_back(currentRandomizationMask); // for (size_t i = 1; i < proofBits; i++) // { // Scalar currMask; // currMask.set_random(); // masksPerBit.push_back(currMask); // masksPerBit[0] = masksPerBit[0].curveSub(currMask.curveMult(Scalar(1 << i))); // } // for (size_t i = 0; i < proofBits; i++) // { // Proof currProof; // std::stringstream oracleInput; // oracleInput << currentFreshGenerator << elGamalBlindGenerator; // mpz_class currBit = proofVal & (1 << i); // Curvepoint currentCommitment = currentFreshGenerator * masksPerBit[i] + elGamalBlindGenerator * Scalar(currBit); // currProof.partialUniversals.push_back(currentCommitment); // oracleInput << currentCommitment; // if (currBit) // { // Scalar u_0, c, c_0, c_1, z_0, z_1; // u_0.set_random(); // c_1.set_random(); // z_1.set_random(); // Curvepoint U_0 = currentFreshGenerator * u_0; // Curvepoint U_1 = currentFreshGenerator * z_1 - currentCommitment * c_1 + elGamalBlindGenerator; // currProof.initParts.push_back(U_0); // currProof.initParts.push_back(U_1); // oracleInput << U_0 << U_1; // c = oracle(oracleInput.str()); // c_0 = c.curveSub(c_1); // z_0 = c_0.curveMult(masksPerBit[i]).curveAdd(u_0); // currProof.challengeParts.push_back(c_0); // currProof.challengeParts.push_back(c_1); // currProof.responseParts.push_back(z_0); // currProof.responseParts.push_back(z_1); // } // else // { // Scalar u_1, c, c_0, c_1, z_0, z_1; // u_1.set_random(); // c_0.set_random(); // z_0.set_random(); // Curvepoint U_0 = currentFreshGenerator * z_0 - currentCommitment * c_0; // Curvepoint U_1 = currentFreshGenerator * u_1; // currProof.initParts.push_back(U_0); // currProof.initParts.push_back(U_1); // oracleInput << U_0 << U_1; // c = oracle(oracleInput.str()); // c_1 = c.curveSub(c_0); // z_1 = c_1.curveMult(masksPerBit[i]).curveAdd(u_1); // currProof.challengeParts.push_back(c_0); // currProof.challengeParts.push_back(c_1); // currProof.responseParts.push_back(z_0); // currProof.responseParts.push_back(z_1); // } // retval.push_back(currProof); // } // return retval; Proof currProof; currProof.basic = "PROOF"; retval.push_back(currProof); return retval; } bool PrsonaClient::verify_reputation_proof(const std::vector& pi, const Curvepoint& shortTermPublicKey, const Scalar& threshold) const { if (pi.empty()) return false; if (!malicious_client) return pi[0].basic == "PROOF"; // if (!verify_ownership_proof(pi[0], shortTermPublicKey)) // return false; // Curvepoint X; // for (size_t i = 1; i < pi.size(); i++) // { // X = X + pi[i].partialUniversals[0] * Scalar(1 << (i - 1)); // std::stringstream oracleInput; // oracleInput << currentFreshGenerator << elGamalBlindGenerator << pi[i].partialUniversals[0]; // oracleInput << pi[i].initParts[0] << pi[i].initParts[1]; // Scalar c = oracle(oracleInput.str()); // if (c != pi[i].challengeParts[0] + pi[i].challengeParts[1]) // return false; // if (currentFreshGenerator * pi[i].responseParts[0] != pi[i].initParts[0] + pi[i].partialUniversals[0] * pi[i].challengeParts[0]) // return false; // if (currentFreshGenerator * pi[i].responseParts[1] != pi[i].initParts[1] + pi[i].partialUniversals[0] * pi[i].challengeParts[1] - elGamalBlindGenerator) // return false; // } // Proof unused, serverProof; // Scalar alsoUnused; // EGCiphertext encryptedScore = servers.get_current_tally(unused, serverProof, shortTermPublicKey, false, alsoUnused); // Scalar negThreshold; // negThreshold = Scalar(0).curveSub(threshold); // Curvepoint scoreCommitment = encryptedScore.encryptedMessage + elGamalBlindGenerator * negThreshold; // if (X != scoreCommitment) // return false; // return true; return pi[0].basic == "PROOF"; } Proof PrsonaClient::generate_ownership_proof() const { Proof retval; if (!malicious_client) { retval.basic = "PROOF"; return retval; } // std::stringstream oracleInput; // Scalar r; // r.set_random(); // Curvepoint shortTermPublicKey = currentFreshGenerator * longTermPrivateKey; // Curvepoint u = currentFreshGenerator * r; // oracleInput << currentFreshGenerator << shortTermPublicKey << u; // Scalar c = oracle(oracleInput.str()); // Scalar z = r.curveAdd(c.curveMult(longTermPrivateKey)); // retval.basic = "PROOF"; // retval.initParts.push_back(u); // retval.responseParts.push_back(z); // return retval; retval.basic = "PROOF"; return retval; } bool PrsonaClient::verify_ownership_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const { if (!malicious_client) return pi.basic == "PROOF"; // Curvepoint u = pi.initParts[0]; // std::stringstream oracleInput; // oracleInput << currentFreshGenerator << shortTermPublicKey << u; // Scalar c = oracle(oracleInput.str()); // Scalar z = pi.responseParts[0]; // return (currentFreshGenerator * z) == (shortTermPublicKey * c + u); return pi.basic == "PROOF"; } void PrsonaClient::decrypt_score(const EGCiphertext& score) { Curvepoint s, hashedDecrypted; s = score.mask * inversePrivateKey; hashedDecrypted = score.encryptedMessage - s; auto lookup = decryption_memoizer.find(hashedDecrypted); if (lookup != decryption_memoizer.end()) { currentScore = lookup->second; // std::cout << "Decrypted score: " << currentScore << std::endl; return; } max_checked++; Curvepoint decryptionCandidate = elGamalBlindGenerator * max_checked; while (decryptionCandidate != hashedDecrypted) { decryption_memoizer[decryptionCandidate] = max_checked; decryptionCandidate = decryptionCandidate + elGamalBlindGenerator; max_checked++; } decryption_memoizer[decryptionCandidate] = max_checked; currentScore = max_checked; // std::cout << "Decrypted score: " << currentScore << std::endl; } Proof PrsonaClient::generate_stpk_proof() const { Proof retval; if (!malicious_client) { retval.basic = "PROOF"; return retval; } retval.basic = "PROOF"; return retval; } bool PrsonaClient::verify_generator_proof(const Proof& pi, const Curvepoint& generator) const { if (!malicious_server) return pi.basic == "PROOF"; return pi.basic == "PROOF"; } bool PrsonaClient::verify_default_tally_proof(const Proof& pi, const EGCiphertext& score) const { if (!malicious_server) return pi.basic == "PROOF"; return pi.basic == "PROOF"; } bool PrsonaClient::verify_valid_tally_proof(const Proof& pi, const EGCiphertext& score) const { if (!malicious_server) return pi.basic == "PROOF"; return pi.basic == "PROOF"; } bool PrsonaClient::verify_default_votes_proof(const Proof& pi, const std::vector& votes) const { if (!malicious_server) return pi.basic == "PROOF"; return pi.basic == "PROOF"; } bool PrsonaClient::verify_valid_votes_proof(const Proof& pi, const std::vector& votes) const { if (!malicious_server) return pi.basic == "PROOF"; return pi.basic == "PROOF"; } Proof PrsonaClient::generate_vote_proof(const std::vector& encryptedVotes, const std::vector& vote) const { Proof retval; if (!malicious_client) { retval.basic = "PROOF"; return retval; } retval.basic = "PROOF"; return retval; } bool PrsonaClient::verify_score_proof(const Proof& pi) const { if (!malicious_server) return pi.basic == "PROOF"; return pi.basic == "PROOF"; }