Merge branch 'microsoft:main' into overvote_and_writeins

This commit is contained in:
jeffspel-crypto 2022-05-05 13:17:30 -07:00 коммит произвёл GitHub
Родитель 1e635a09c4 53a22dd242
Коммит 8c7c6162bd
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 96 добавлений и 55 удалений

Просмотреть файл

@ -115,10 +115,9 @@ namespace electionguard
unique_ptr<Triple> triple1;
unique_ptr<Triple> triple2;
unique_ptr<Quadruple> quad;
bool populated = false;
public:
explicit TwoTriplesAndAQuadruple() { populated = false; }
explicit TwoTriplesAndAQuadruple() {}
TwoTriplesAndAQuadruple(unique_ptr<Triple> in_triple1, unique_ptr<Triple> in_triple2,
unique_ptr<Quadruple> in_quad);
TwoTriplesAndAQuadruple(const TwoTriplesAndAQuadruple &other);
@ -134,8 +133,6 @@ namespace electionguard
unique_ptr<Quadruple> get_quad() { return quad->clone(); }
bool isPopulated() { return populated; }
unique_ptr<TwoTriplesAndAQuadruple> clone();
};
@ -225,6 +222,14 @@ namespace electionguard
/// </summary>
static std::unique_ptr<TwoTriplesAndAQuadruple> getTwoTriplesAndAQuadruple();
/// <summary>
/// Get the next triple from the triple queue.
/// This method is called by hashedElgamalEncrypt in order to get
/// the precomputed value to perform the hashed elgamal encryption.
/// <returns>std::unique_ptr<Triple></returns>
/// </summary>
static std::unique_ptr<Triple> getTriple();
/// <summary>
/// Empty the precomputed values queues.
/// <returns>void</returns>
@ -236,7 +241,7 @@ namespace electionguard
static std::mutex queue_lock;
bool populate_OK = false;
std::queue<std::unique_ptr<Triple>> triple_queue;
std::queue<std::unique_ptr<Quadruple>> quadruple_queue;
std::queue<std::unique_ptr<TwoTriplesAndAQuadruple>> twoTriplesAndAQuadruple_queue;
};
} // namespace electionguard

Просмотреть файл

@ -581,13 +581,24 @@ namespace electionguard
auto *alpha = message.getPad();
auto *beta = message.getData();
// Pick a random number in Q.
// Derive nonce from seed and the constant string below
auto nonces = make_unique<Nonces>(seed, "constant-chaum-pedersen-proof");
auto u = nonces->get(0);
unique_ptr<ElementModQ> u;
// Compute the NIZKP
auto a = g_pow_p(*u); //𝑔^𝑢 mod 𝑝
auto b = pow_mod_p(k, *u); // 𝐾^𝑢 mod 𝑝
unique_ptr<ElementModP> a; //𝑔^𝑢 mod 𝑝
unique_ptr<ElementModP> b; // 𝐾^𝑢 mod 𝑝
// check if the are precompute values rather than doing the exponentiations here
unique_ptr<Triple> triple = PrecomputeBufferContext::getTriple();
if (triple != nullptr) {
u = triple->get_exp();
a = triple->get_g_to_exp();
b = triple->get_pubkey_to_exp();
} else {
u = nonces->get(0);
a = g_pow_p(*u); //𝑔^𝑢 mod 𝑝
b = pow_mod_p(k, *u); // 𝐾^𝑢 mod 𝑝
}
// sha256(𝑄', A, B, a, b)
auto c =

Просмотреть файл

@ -236,7 +236,7 @@ namespace electionguard
{
unique_ptr<CiphertextBallotSelection> encrypted = NULL;
unique_ptr<ElGamalCiphertext> ciphertext;
unique_ptr<TwoTriplesAndAQuadruple> precomputedTwoTriplesAndAQuad;
unique_ptr<TwoTriplesAndAQuadruple> precomputedTwoTriplesAndAQuad = nullptr;
// Validate Input
if (!selection.isValid(description.getObjectId())) {
@ -258,7 +258,7 @@ namespace electionguard
precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
// check if we found the precomputed values needed
if (precomputedTwoTriplesAndAQuad->isPopulated()) {
if (precomputedTwoTriplesAndAQuad != nullptr) {
auto triple1 = precomputedTwoTriplesAndAQuad->get_triple1();
auto g_to_exp = triple1->get_g_to_exp();
auto pubkey_to_exp = triple1->get_pubkey_to_exp();

Просмотреть файл

@ -144,7 +144,6 @@ namespace electionguard
this->triple1 = move(triple1);
this->triple2 = move(triple2);
this->quad = move(quad);
populated = true;
}
TwoTriplesAndAQuadruple::TwoTriplesAndAQuadruple(const TwoTriplesAndAQuadruple &other)
@ -204,9 +203,10 @@ namespace electionguard
// This loop goes through until the queues are full but can be stopped
// between generations of two triples and a quad. By full it means
// we check how many quads are in the queue, to start with we will
// try 500 and see how that works. If the vendor wanted to pass the
// try 5000 and see how that works. If the vendor wanted to pass the
// queue size in we could use that.
// for now we just go through the loop once
int iteration_count = 0;
do {
// TODO - Can we tolerate not returning until we have finished
// generating two triples and a quadruple?
@ -220,16 +220,31 @@ namespace electionguard
unique_ptr<Triple> triple2 = make_unique<Triple>(elgamalPublicKey);
unique_ptr<Quadruple> quad = make_unique<Quadruple>(elgamalPublicKey);
getInstance().triple_queue.push(move(triple1));
unique_ptr<TwoTriplesAndAQuadruple> twoTriplesAndAQuadruple =
make_unique<TwoTriplesAndAQuadruple>(move(triple1), move(triple2), move(quad));
getInstance().triple_queue.push(move(triple2));
getInstance().quadruple_queue.push(move(quad));
getInstance().twoTriplesAndAQuadruple_queue.push(move(twoTriplesAndAQuadruple));
// This is very rudimentary. We can add a more complex algorithm in
// the future, that would look at the queues and increase production if one
// is getting lower than expected.
// Every third iteration we generate two extra triples, one for use with
// the contest constant chaum pedersen proof and one for hashed elgamal encryption
// we need less of these because this exponentiation is done only every contest
// encryption whereas the two triples and a quadruple is used every selection
// encryption. The generating two triples every third iteration is a guess
// on how many precomputes we will need.
if ((iteration_count % 3) == 0) {
unique_ptr<Triple> contest_triple1 = make_unique<Triple>(elgamalPublicKey);
getInstance().triple_queue.push(move(contest_triple1));
unique_ptr<Triple> contest_triple2 = make_unique<Triple>(elgamalPublicKey);
getInstance().triple_queue.push(move(contest_triple2));
}
iteration_count++;
} else {
return;
}
} while (getInstance().quadruple_queue.size() < getInstance().max);
} while (getInstance().twoTriplesAndAQuadruple_queue.size() < getInstance().max);
}
void PrecomputeBufferContext::stop_populate() { getInstance().populate_OK = false; }
@ -238,29 +253,36 @@ namespace electionguard
uint32_t PrecomputeBufferContext::get_current_queue_size()
{
return getInstance().quadruple_queue.size();
return getInstance().twoTriplesAndAQuadruple_queue.size();
}
std::unique_ptr<TwoTriplesAndAQuadruple> PrecomputeBufferContext::getTwoTriplesAndAQuadruple()
{
unique_ptr<TwoTriplesAndAQuadruple> result = make_unique<TwoTriplesAndAQuadruple>();
unique_ptr<TwoTriplesAndAQuadruple> result = nullptr;
// take a lock while we get the triples and a quadruple
std::lock_guard<std::mutex> lock(queue_lock);
// make sure there are enough in the queues
if ((getInstance().triple_queue.size() >= 2) &&
(getInstance().quadruple_queue.size() >= 1)) {
if (!getInstance().twoTriplesAndAQuadruple_queue.empty()) {
result = std::move(getInstance().twoTriplesAndAQuadruple_queue.front());
getInstance().twoTriplesAndAQuadruple_queue.pop();
}
unique_ptr<Triple> triple1 = std::move(getInstance().triple_queue.front());
return result;
}
std::unique_ptr<Triple> PrecomputeBufferContext::getTriple()
{
unique_ptr<Triple> result = nullptr;
// take a lock while we get the triples and a quadruple
std::lock_guard<std::mutex> lock(queue_lock);
// make sure there are enough in the queues
if (!getInstance().triple_queue.empty()) {
result = std::move(getInstance().triple_queue.front());
getInstance().triple_queue.pop();
unique_ptr<Triple> triple2 = std::move(getInstance().triple_queue.front());
getInstance().triple_queue.pop();
unique_ptr<Quadruple> quad = std::move(getInstance().quadruple_queue.front());
getInstance().quadruple_queue.pop();
result = make_unique<TwoTriplesAndAQuadruple>(move(triple1), move(triple2), move(quad));
}
return result;
@ -269,11 +291,13 @@ namespace electionguard
void PrecomputeBufferContext::empty_queues()
{
std::lock_guard<std::mutex> lock(queue_lock);
uint32_t size = getInstance().quadruple_queue.size();
for (int i = 0; i < (int)size; i++) {
uint32_t triple_size = getInstance().triple_queue.size();
for (int i = 0; i < (int)triple_size; i++) {
getInstance().triple_queue.pop();
getInstance().triple_queue.pop();
getInstance().quadruple_queue.pop();
}
uint32_t twoTriplesAndAQuadruple_size = getInstance().twoTriplesAndAQuadruple_queue.size();
for (int i = 0; i < (int)twoTriplesAndAQuadruple_size; i++) {
getInstance().twoTriplesAndAQuadruple_queue.pop();
}
}

Просмотреть файл

@ -46,7 +46,7 @@ BENCHMARK_DEFINE_F(ElGamalEncryptPrecomputedFixture, ElGamalEncryptPrecomputed)(
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
// check if we found the precomputed values needed
if (precomputedTwoTriplesAndAQuad->isPopulated()) {
if (precomputedTwoTriplesAndAQuad != nullptr) {
auto triple1 = precomputedTwoTriplesAndAQuad->get_triple1();
auto g_to_exp = triple1->get_g_to_exp();
auto pubkey_to_exp = triple1->get_pubkey_to_exp();
@ -102,7 +102,7 @@ class ChaumPedersenPrecomputedFixture : public benchmark::Fixture
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
// check if we found the precomputed values needed
if (precomputedTwoTriplesAndAQuad->isPopulated()) {
if (precomputedTwoTriplesAndAQuad != nullptr) {
disjunctive = DisjunctiveChaumPedersenProof::make_with_precomputed(
*message, move(precomputedTwoTriplesAndAQuad), ONE_MOD_Q(), 1);
}
@ -130,7 +130,7 @@ BENCHMARK_DEFINE_F(ChaumPedersenPrecomputedFixture, disjunctiveChaumPedersenPrec
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
// check if we found the precomputed values needed
if (precomputedTwoTriplesAndAQuad->isPopulated()) {
if (precomputedTwoTriplesAndAQuad != nullptr) {
DisjunctiveChaumPedersenProof::make_with_precomputed(
*message, move(precomputedTwoTriplesAndAQuad), ONE_MOD_Q(), 1);
}
@ -147,7 +147,7 @@ BENCHMARK_DEFINE_F(ChaumPedersenPrecomputedFixture, disjunctiveChaumPedersenPrec
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
// check if we found the precomputed values needed
if (precomputedTwoTriplesAndAQuad->isPopulated()) {
if (precomputedTwoTriplesAndAQuad != nullptr) {
auto item = DisjunctiveChaumPedersenProofPrecomputedHarness::make_zero_with_precomputed(
*message, move(precomputedTwoTriplesAndAQuad), ONE_MOD_Q());
}
@ -164,7 +164,7 @@ BENCHMARK_DEFINE_F(ChaumPedersenPrecomputedFixture, disjunctiveChaumPedersenPrec
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
// check if we found the precomputed values needed
if (precomputedTwoTriplesAndAQuad->isPopulated()) {
if (precomputedTwoTriplesAndAQuad != nullptr) {
auto item = DisjunctiveChaumPedersenProofPrecomputedHarness::make_one_with_precomputed(
*message, move(precomputedTwoTriplesAndAQuad), ONE_MOD_Q());
}
@ -202,7 +202,7 @@ class CiphertextBallotSelectionPrecomputedFixture : public benchmark::Fixture
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
// check if we found the precomputed values needed
if (precomputedTwoTriplesAndAQuad->isPopulated()) {
if (precomputedTwoTriplesAndAQuad != nullptr) {
auto triple1 = precomputedTwoTriplesAndAQuad->get_triple1();
auto g_to_exp = triple1->get_g_to_exp();
auto pubkey_to_exp = triple1->get_pubkey_to_exp();
@ -236,7 +236,7 @@ BENCHMARK_DEFINE_F(CiphertextBallotSelectionPrecomputedFixture,
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
// check if we found the precomputed values needed
if (precomputedTwoTriplesAndAQuad->isPopulated()) {
if (precomputedTwoTriplesAndAQuad != nullptr) {
auto triple1 = precomputedTwoTriplesAndAQuad->get_triple1();
auto g_to_exp = triple1->get_g_to_exp();
auto pubkey_to_exp = triple1->get_pubkey_to_exp();
@ -340,6 +340,7 @@ BENCHMARK_DEFINE_F(PrecomputeFixture, precomputed)
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
}
PrecomputeBufferContext::empty_queues();
}
BENCHMARK_REGISTER_F(PrecomputeFixture, precomputed)
@ -395,6 +396,7 @@ class EncryptBallotPrecomputeFixture : public benchmark::Fixture
BENCHMARK_DEFINE_F(EncryptBallotPrecomputeFixture, encryptBallotPrecompute_Full_NoProofCheck)(benchmark::State &state)
{
PrecomputeBufferContext::stop_populate();
while (state.KeepRunning()) {
auto result = encryptBallot(*ballot, *internal, *context, *device->getHash(),
make_unique<ElementModQ>(*nonce), 0UL, false);

Просмотреть файл

@ -146,13 +146,9 @@ TEST_CASE("Disjunctive CP Proof simple valid inputs generate valid proofs")
auto precomputedTwoTriplesAndAQuad4 = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
CHECK(precomputedTwoTriplesAndAQuad1 != nullptr);
CHECK(precomputedTwoTriplesAndAQuad1->isPopulated() == true);
CHECK(precomputedTwoTriplesAndAQuad2 != nullptr);
CHECK(precomputedTwoTriplesAndAQuad2->isPopulated() == true);
CHECK(precomputedTwoTriplesAndAQuad3 != nullptr);
CHECK(precomputedTwoTriplesAndAQuad3->isPopulated() == true);
CHECK(precomputedTwoTriplesAndAQuad4 != nullptr);
CHECK(precomputedTwoTriplesAndAQuad4->isPopulated() == true);
auto triple1_1 = precomputedTwoTriplesAndAQuad1->get_triple1();
auto triple1_2 = precomputedTwoTriplesAndAQuad2->get_triple1();
@ -194,6 +190,7 @@ TEST_CASE("Disjunctive CP Proof simple valid inputs generate valid proofs")
false);
CHECK(fourthMessageOneProof->isValid(*fourthMessage, *keypair->getPublicKey(), ONE_MOD_Q()) ==
true);
PrecomputeBufferContext::empty_queues();
}
TEST_CASE("Disjunctive CP Proof encryption of zero with precomputed values")
@ -213,9 +210,7 @@ TEST_CASE("Disjunctive CP Proof encryption of zero with precomputed values")
auto precomputedTwoTriplesAndAQuad2 = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
CHECK(precomputedTwoTriplesAndAQuad1 != nullptr);
CHECK(precomputedTwoTriplesAndAQuad1->isPopulated() == true);
CHECK(precomputedTwoTriplesAndAQuad2 != nullptr);
CHECK(precomputedTwoTriplesAndAQuad2->isPopulated() == true);
auto triple1_1 = precomputedTwoTriplesAndAQuad1->get_triple1();
auto triple1_2 = precomputedTwoTriplesAndAQuad2->get_triple1();
@ -233,6 +228,7 @@ TEST_CASE("Disjunctive CP Proof encryption of zero with precomputed values")
CHECK(proof->isValid(*message1, *keypair->getPublicKey(), ONE_MOD_Q()) == true);
CHECK(badProof->isValid(*message2, *keypair->getPublicKey(), ONE_MOD_Q()) == false);
PrecomputeBufferContext::empty_queues();
}
TEST_CASE("Disjunctive CP Proof encryption of one with precomputed values")
@ -252,9 +248,7 @@ TEST_CASE("Disjunctive CP Proof encryption of one with precomputed values")
auto precomputedTwoTriplesAndAQuad2 = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
CHECK(precomputedTwoTriplesAndAQuad1 != nullptr);
CHECK(precomputedTwoTriplesAndAQuad1->isPopulated() == true);
CHECK(precomputedTwoTriplesAndAQuad2 != nullptr);
CHECK(precomputedTwoTriplesAndAQuad2->isPopulated() == true);
auto triple1_1 = precomputedTwoTriplesAndAQuad1->get_triple1();
auto triple1_2 = precomputedTwoTriplesAndAQuad2->get_triple1();
@ -272,4 +266,5 @@ TEST_CASE("Disjunctive CP Proof encryption of one with precomputed values")
CHECK(proof->isValid(*message1, *keypair->getPublicKey(), ONE_MOD_Q()) == true);
CHECK(badProof->isValid(*message2, *keypair->getPublicKey(), ONE_MOD_Q()) == false);
PrecomputeBufferContext::empty_queues();
}

Просмотреть файл

@ -83,7 +83,6 @@ TEST_CASE("elgamalEncrypt simple encrypt 0 compared with elgamalEncrypt_with_pre
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
CHECK(precomputedTwoTriplesAndAQuad != nullptr);
CHECK(precomputedTwoTriplesAndAQuad->isPopulated() == true);
auto triple1 = precomputedTwoTriplesAndAQuad->get_triple1();
@ -98,6 +97,7 @@ TEST_CASE("elgamalEncrypt simple encrypt 0 compared with elgamalEncrypt_with_pre
CHECK((0UL == decrypted1));
auto decrypted2 = cipherText2->decrypt(secret);
CHECK((0UL == decrypted2));
PrecomputeBufferContext::empty_queues();
}
TEST_CASE("elgamalEncrypt_with_precomputed simple encrypt 0")
@ -118,7 +118,6 @@ TEST_CASE("elgamalEncrypt_with_precomputed simple encrypt 0")
auto precomputedTwoTriplesAndAQuad = PrecomputeBufferContext::getTwoTriplesAndAQuadruple();
CHECK(precomputedTwoTriplesAndAQuad != nullptr);
CHECK(precomputedTwoTriplesAndAQuad->isPopulated() == true);
auto triple1 = precomputedTwoTriplesAndAQuad->get_triple1();
CHECK(triple1 != nullptr);
@ -128,6 +127,7 @@ TEST_CASE("elgamalEncrypt_with_precomputed simple encrypt 0")
auto decrypted = cipherText->decrypt(secret);
CHECK((0UL == decrypted));
PrecomputeBufferContext::empty_queues();
}
TEST_CASE("elgamalEncrypt simple encrypt 1 decrypts with secret")
@ -482,4 +482,5 @@ TEST_CASE("elgamalEncrypt_with_precomputed encrypt 1, decrypts with secret")
auto decrypted = cipherText->decrypt(*secret);
CHECK(1UL == decrypted);
PrecomputeBufferContext::empty_queues();
}

Просмотреть файл

@ -81,6 +81,8 @@ TEST_CASE("Encrypt simple selection using precomputed values succeeds")
CHECK(result->isValidEncryption(*hashContext, *keypair->getPublicKey(), ONE_MOD_Q()) == true);
CHECK(result->getProof()->isValid(*result->getCiphertext(), *keypair->getPublicKey(),
ONE_MOD_Q()) == true);
// need to empty the queues because future tests don't use the same keys
PrecomputeBufferContext::empty_queues();
}
TEST_CASE("Encrypt simple selection malformed data fails")
@ -130,7 +132,7 @@ TEST_CASE("Encrypt PlaintextBallot with EncryptionMediator against constructed "
auto device = make_unique<EncryptionDevice>(12345UL, 23456UL, 34567UL, "Location");
auto mediator = make_unique<EncryptionMediator>(*internal, *context, *device);
// Act
auto plaintext = BallotGenerator::getFakeBallot(*internal);
// Log::debug(plaintext->toJson());
@ -420,14 +422,14 @@ TEST_CASE("Encrypt simple ballot from file succeeds with precomputed values")
auto ballot = BallotGenerator::getFakeBallot(*internal);
// cause a two triples and a quad to be populated
PrecomputeBufferContext::init(50);
PrecomputeBufferContext::init(100);
PrecomputeBufferContext::populate(*keypair->getPublicKey());
PrecomputeBufferContext::stop_populate();
uint32_t max_precomputed_queue_size = PrecomputeBufferContext::get_max_queue_size();
uint32_t current_precomputed_queue_size = PrecomputeBufferContext::get_current_queue_size();
CHECK(50 == max_precomputed_queue_size);
CHECK(50 == current_precomputed_queue_size);
CHECK(100 == max_precomputed_queue_size);
CHECK(100 == current_precomputed_queue_size);
// Act
auto ciphertext = encryptBallot(*ballot, *internal, *context, *device->getHash(),
@ -438,4 +440,5 @@ TEST_CASE("Encrypt simple ballot from file succeeds with precomputed values")
// Assert
CHECK(ciphertext->isValidEncryption(*context->getManifestHash(), *keypair->getPublicKey(),
*context->getCryptoExtendedBaseHash()) == true);
PrecomputeBufferContext::empty_queues();
}