Browse Source

adding more detailed tests

tristangurtler 3 years ago
parent
commit
e34a304f68
5 changed files with 346 additions and 48 deletions
  1. 5 0
      bgn2/inc/BGN.hpp
  2. 7 0
      bgn2/inc/PublicKey.hpp
  3. 20 0
      bgn2/src/BGN.cpp
  4. 30 44
      bgn2/src/PublicKey.cpp
  5. 284 4
      bgn2/src/main.cpp

+ 5 - 0
bgn2/inc/BGN.hpp

@@ -21,6 +21,11 @@ class BGN
 		Quadripoint homomorphic_addition(const Quadripoint& a, const Quadripoint& b) const;
 		Quadripoint homomorphic_multiplication(const CurveBipoint& a, const TwistBipoint& b) const;
 
+        CurveBipoint homomorphic_addition_no_rerandomize(const CurveBipoint& a, const CurveBipoint& b) const;
+        TwistBipoint homomorphic_addition_no_rerandomize(const TwistBipoint& a, const TwistBipoint& b) const;
+        Quadripoint homomorphic_addition_no_rerandomize(const Quadripoint& a, const Quadripoint& b) const;
+        Quadripoint homomorphic_multiplication_no_rerandomize(const CurveBipoint& a, const TwistBipoint& b) const;
+
 		Scalar decrypt(const CurveBipoint& ciphertext);
         Scalar decrypt(const TwistBipoint& ciphertext);
         Scalar decrypt(const Quadripoint & ciphertext);

+ 7 - 0
bgn2/inc/PublicKey.hpp

@@ -19,6 +19,11 @@ class BGNPublicKey
 		Quadripoint homomorphic_addition(const Quadripoint& a, const Quadripoint& b) const;
 		Quadripoint homomorphic_multiplication(const CurveBipoint& a, const TwistBipoint& b) const;
 
+		CurveBipoint homomorphic_addition_no_rerandomize(const CurveBipoint& a, const CurveBipoint& b) const;
+		TwistBipoint homomorphic_addition_no_rerandomize(const TwistBipoint& a, const TwistBipoint& b) const;
+		Quadripoint homomorphic_addition_no_rerandomize(const Quadripoint& a, const Quadripoint& b) const;
+		Quadripoint homomorphic_multiplication_no_rerandomize(const CurveBipoint& a, const TwistBipoint& b) const;
+
 		CurveBipoint rerandomize(const CurveBipoint& a) const;
 		TwistBipoint rerandomize(const TwistBipoint& a) const;
 		Quadripoint rerandomize(const Quadripoint& a) const;
@@ -40,6 +45,8 @@ class BGNPublicKey
 		TwistBipoint bipoint_twistgen; // h
 		CurveBipoint bipoint_curve_subgroup_gen; // (g^(a1), g^(b1))
 		TwistBipoint bipoint_twist_subgroup_gen; // (h^(a2), h^(b2))
+		Quadripoint quadripoint_subgroup_gen_a; // e(g, h1)
+		Quadripoint quadripoint_subgroup_gen_b; // e(g1, h)
 };
 
 #endif

+ 20 - 0
bgn2/src/BGN.cpp

@@ -103,6 +103,26 @@ Quadripoint BGN::homomorphic_multiplication(const CurveBipoint& a, const TwistBi
 	return public_key.homomorphic_multiplication(a, b);
 }
 
+CurveBipoint BGN::homomorphic_addition_no_rerandomize(const CurveBipoint& a, const CurveBipoint& b) const
+{
+    return public_key.homomorphic_addition_no_rerandomize(a, b);
+}
+
+TwistBipoint BGN::homomorphic_addition_no_rerandomize(const TwistBipoint& a, const TwistBipoint& b) const
+{
+    return public_key.homomorphic_addition_no_rerandomize(a, b);
+}
+
+Quadripoint BGN::homomorphic_addition_no_rerandomize(const Quadripoint& a, const Quadripoint& b) const
+{
+    return public_key.homomorphic_addition_no_rerandomize(a, b);
+}
+
+Quadripoint BGN::homomorphic_multiplication_no_rerandomize(const CurveBipoint& a, const TwistBipoint& b) const
+{
+    return public_key.homomorphic_multiplication_no_rerandomize(a, b);
+}
+
 CurveBipoint BGN::rerandomize(const CurveBipoint& G_element) const
 {
     return public_key.rerandomize(G_element);

+ 30 - 44
bgn2/src/PublicKey.cpp

@@ -38,58 +38,42 @@ void BGNPublicKey::encrypt(CurveBipoint& G_element, TwistBipoint& H_element, con
 
 CurveBipoint BGNPublicKey::homomorphic_addition(const CurveBipoint& a, const CurveBipoint& b) const
 {
-    Scalar lambda;
-    lambda.set_random();
-
-    CurveBipoint random_mask;
-    random_mask = bipoint_curve_subgroup_gen * lambda;
-
-    return a + b + random_mask;
+    return rerandomize(homomorphic_addition_no_rerandomize(a, b));
 }
 
 TwistBipoint BGNPublicKey::homomorphic_addition(const TwistBipoint& a, const TwistBipoint& b) const
 {
-    Scalar lambda;
-    lambda.set_random();
-
-    TwistBipoint random_mask;
-    random_mask = bipoint_twist_subgroup_gen * lambda;
-
-    return a + b + random_mask;
+    return rerandomize(homomorphic_addition_no_rerandomize(a, b));
 }
 
 Quadripoint BGNPublicKey::homomorphic_addition(const Quadripoint& a, const Quadripoint& b) const
 {
-    Quadripoint random_mask;
-    CurveBipoint random_mask_curve;
-    TwistBipoint random_mask_twist;
-    
-    Scalar lambda1, lambda2;
-    lambda1.set_random();
-    lambda2.set_random();
+    return rerandomize(homomorphic_addition_no_rerandomize(a, b));
+}
 
-    random_mask_curve = bipoint_curve_subgroup_gen * lambda1;
-    random_mask_twist = bipoint_twist_subgroup_gen * lambda2;
-    random_mask = pairing(bipoint_curvegen, random_mask_twist) + pairing(random_mask_curve, bipoint_twistgen);
+Quadripoint BGNPublicKey::homomorphic_multiplication(const CurveBipoint& a, const TwistBipoint& b) const
+{
+    return rerandomize(homomorphic_multiplication_no_rerandomize(a, b));
+}
 
-    return a + b + random_mask;
+CurveBipoint BGNPublicKey::homomorphic_addition_no_rerandomize(const CurveBipoint& a, const CurveBipoint& b) const
+{
+    return a + b;
 }
 
-Quadripoint BGNPublicKey::homomorphic_multiplication(const CurveBipoint& a, const TwistBipoint& b) const
+TwistBipoint BGNPublicKey::homomorphic_addition_no_rerandomize(const TwistBipoint& a, const TwistBipoint& b) const
 {
-    Quadripoint random_mask;
-    CurveBipoint random_mask_curve;
-    TwistBipoint random_mask_twist;
-    
-    Scalar lambda1, lambda2;
-    lambda1.set_random();
-    lambda2.set_random();
+    return a + b;
+}
 
-    random_mask_curve = bipoint_curve_subgroup_gen * lambda1;
-    random_mask_twist = bipoint_twist_subgroup_gen * lambda2;
-    random_mask = pairing(bipoint_curvegen, random_mask_twist) + pairing(random_mask_curve, bipoint_twistgen);
+Quadripoint BGNPublicKey::homomorphic_addition_no_rerandomize(const Quadripoint& a, const Quadripoint& b) const
+{
+    return a + b;
+}
 
-    return pairing(a, b) + random_mask;
+Quadripoint BGNPublicKey::homomorphic_multiplication_no_rerandomize(const CurveBipoint& a, const TwistBipoint& b) const
+{
+    return pairing(a, b);
 }
 
 CurveBipoint BGNPublicKey::rerandomize(const CurveBipoint& a) const
@@ -116,17 +100,12 @@ TwistBipoint BGNPublicKey::rerandomize(const TwistBipoint& a) const
 
 Quadripoint BGNPublicKey::rerandomize(const Quadripoint& a) const
 {
-    Quadripoint random_mask;
-    CurveBipoint random_mask_curve;
-    TwistBipoint random_mask_twist;
-    
     Scalar lambda1, lambda2;
     lambda1.set_random();
     lambda2.set_random();
 
-    random_mask_curve = bipoint_curve_subgroup_gen * lambda1;
-    random_mask_twist = bipoint_twist_subgroup_gen * lambda2;
-    random_mask = pairing(bipoint_curvegen, random_mask_twist) + pairing(random_mask_curve, bipoint_twistgen);
+    Quadripoint random_mask;
+    random_mask = quadripoint_subgroup_gen_a * lambda1 + quadripoint_subgroup_gen_b * lambda2;
 
     return a + random_mask;
 }
@@ -157,6 +136,8 @@ std::ostream& operator<<(std::ostream& os, const BGNPublicKey& output)
     os << output.bipoint_twistgen;
     os << output.bipoint_curve_subgroup_gen;
     os << output.bipoint_twist_subgroup_gen;
+    os << output.quadripoint_subgroup_gen_a;
+    os << output.quadripoint_subgroup_gen_b;
 
     return os;
 }
@@ -167,6 +148,8 @@ std::istream& operator>>(std::istream& is, BGNPublicKey& input)
     is >> input.bipoint_twistgen;
     is >> input.bipoint_curve_subgroup_gen;
     is >> input.bipoint_twist_subgroup_gen;
+    is >> input.quadripoint_subgroup_gen_a;
+    is >> input.quadripoint_subgroup_gen_b;
 
     return is;
 }
@@ -181,4 +164,7 @@ void BGNPublicKey::set(const CurveBipoint& g, const TwistBipoint& h, const Curve
     
     bipoint_curve_subgroup_gen = g1;
     bipoint_twist_subgroup_gen = h1;
+
+    quadripoint_subgroup_gen_a = pairing(g, h1);
+    quadripoint_subgroup_gen_b = pairing(g1, h);
 }

+ 284 - 4
bgn2/src/main.cpp

@@ -182,6 +182,90 @@ double testQuadDecryptSpeed(default_random_engine& generator)
     return time_span.count();
 }
 
+double testCurveDecryptSpeed(size_t max)
+{
+    BGN system;
+
+    vector<Scalar> testVals;
+    for (size_t i = 0; i < max; i++)
+        testVals.push_back(Scalar(i));
+
+    vector<CurveBipoint> encryptions(max);
+    vector<Scalar> decryptions(max);
+    
+    for (size_t i = 0; i < max; i++)
+        system.encrypt(encryptions[i], testVals[i]);
+
+    chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
+
+    for (size_t i = 0; i < max; i++)
+        decryptions[i] = system.decrypt(encryptions[i]);
+
+    chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
+    chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
+
+    return time_span.count();
+}
+
+double testTwistDecryptSpeed(size_t max)
+{
+    BGN system;
+
+    vector<Scalar> testVals;
+    for (size_t i = 0; i < max; i++)
+        testVals.push_back(Scalar(i));
+
+    vector<TwistBipoint> encryptions(max);
+    vector<Scalar> decryptions(max);
+    
+    for (size_t i = 0; i < max; i++)
+        system.encrypt(encryptions[i], testVals[i]);
+
+    chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
+
+    for (size_t i = 0; i < max; i++)
+        decryptions[i] = system.decrypt(encryptions[i]);
+
+    chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
+    chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
+
+    return time_span.count();
+}
+
+double testQuadDecryptSpeed(size_t max)
+{
+    BGN system;
+
+    vector<Scalar> testVals;
+    for (size_t i = 0; i < max; i++)
+        testVals.push_back(Scalar(i));
+    
+    Scalar one(1);
+
+    TwistBipoint oneEncryption;
+    vector<CurveBipoint> firstEncryptions(max);
+    vector<Quadripoint> realEncryptions(max);
+    vector<Scalar> decryptions(max);
+    
+    system.encrypt(oneEncryption, one);
+
+    for (size_t i = 0; i < max; i++)
+    {
+        system.encrypt(firstEncryptions[i], testVals[i]);
+        realEncryptions[i] = system.homomorphic_multiplication(firstEncryptions[i], oneEncryption);
+    }   
+
+    chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
+
+    for (size_t i = 0; i < max; i++)
+        decryptions[i] = system.decrypt(realEncryptions[i]);
+
+    chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
+    chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
+
+    return time_span.count();
+}
+
 bool testAddition(int x, int y)
 {
     bool retval;
@@ -267,7 +351,7 @@ double testCurveAdditionSpeed(default_random_engine& generator)
     chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
 
     for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
-        encSums[i] = system.homomorphic_addition(encXs[i], encYs[i]);
+        encSums[i] = system.homomorphic_addition_no_rerandomize(encXs[i], encYs[i]);
 
     chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
     chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
@@ -302,7 +386,7 @@ double testTwistAdditionSpeed(default_random_engine& generator)
     chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
 
     for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
-        encSums[i] = system.homomorphic_addition(encXs[i], encYs[i]);
+        encSums[i] = system.homomorphic_addition_no_rerandomize(encXs[i], encYs[i]);
 
     chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
     chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
@@ -346,7 +430,7 @@ double testQuadAdditionSpeed(default_random_engine& generator)
     chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
 
     for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
-        encSums[i] = system.homomorphic_addition(realEncXs[i], realEncYs[i]);
+        encSums[i] = system.homomorphic_addition_no_rerandomize(realEncXs[i], realEncYs[i]);
 
     chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
     chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
@@ -413,7 +497,139 @@ double testMultiplicationSpeed(default_random_engine& generator)
     chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
 
     for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
-        encProducts[i] = system.homomorphic_multiplication(encXs[i], encYs[i]);
+        encProducts[i] = system.homomorphic_multiplication_no_rerandomize(encXs[i], encYs[i]);
+
+    chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
+    chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
+
+    return time_span.count();
+}
+
+bool testRerandomize(int x)
+{
+    bool retval;
+
+    BGN system;
+
+    Scalar testVal(x);
+    Scalar one(1);
+    Scalar decrypted;
+
+    CurveBipoint curveEnc, curveRand, curveOne;
+    TwistBipoint twistEnc, twistRand, twistOne;
+    Quadripoint quadEncA, quadEncB, quadRandA, quadRandB;
+
+    system.encrypt(curveEnc, testVal);
+    system.encrypt(curveOne, one);
+    system.encrypt(twistEnc, testVal);
+    system.encrypt(twistOne, one);
+
+    quadEncA = system.homomorphic_multiplication(curveEnc, twistOne);
+    quadEncB = system.homomorphic_multiplication(curveOne, twistEnc);
+
+    curveRand = system.rerandomize(curveEnc);
+    twistRand = system.rerandomize(twistEnc);
+    quadRandA = system.rerandomize(quadEncA);
+    quadRandB = system.rerandomize(quadEncB);
+    
+    decrypted = system.decrypt(curveRand);
+    retval = (decrypted == testVal);
+
+    decrypted = system.decrypt(twistRand);
+    retval = retval && (decrypted == testVal);
+
+    decrypted = system.decrypt(quadRandA);
+    retval = retval && (decrypted == testVal);
+
+    decrypted = system.decrypt(quadRandB);
+    retval = retval && (decrypted == testVal);
+
+    return retval;
+}
+
+double testCurveRerandomizeSpeed(default_random_engine& generator)
+{
+    BGN system;
+
+    uniform_int_distribution<int> distribution(0, MAX_VALUE_IN_TEST);
+
+    vector<Scalar> testVals;
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+        testVals.push_back(Scalar(distribution(generator)));
+
+    vector<CurveBipoint> encryptions(NUM_RUNS_PER_TEST);
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+        system.encrypt(encryptions[i], testVals[i]);
+
+    vector<CurveBipoint> rerandomizations(NUM_RUNS_PER_TEST);
+
+    chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
+    
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+        rerandomizations[i] = system.rerandomize(encryptions[i]);
+
+    chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
+    chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
+
+    return time_span.count();
+}
+
+double testTwistRerandomizeSpeed(default_random_engine& generator)
+{
+    BGN system;
+
+    uniform_int_distribution<int> distribution(0, MAX_VALUE_IN_TEST);
+
+    vector<Scalar> testVals;
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+        testVals.push_back(Scalar(distribution(generator)));
+
+    vector<TwistBipoint> encryptions(NUM_RUNS_PER_TEST);
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+        system.encrypt(encryptions[i], testVals[i]);
+
+    vector<TwistBipoint> rerandomizations(NUM_RUNS_PER_TEST);
+
+    chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
+    
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+        rerandomizations[i] = system.rerandomize(encryptions[i]);
+
+    chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
+    chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
+
+    return time_span.count();
+}
+
+double testQuadRerandomizeSpeed(default_random_engine& generator)
+{
+    BGN system;
+
+    uniform_int_distribution<int> distribution(0, MAX_VALUE_IN_TEST);
+
+    vector<Scalar> testVals;
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+        testVals.push_back(Scalar(distribution(generator)));
+    
+    Scalar one(1);
+
+    TwistBipoint oneEncryption;
+    vector<CurveBipoint> firstEncryptions(NUM_RUNS_PER_TEST);
+    vector<Quadripoint> realEncryptions(NUM_RUNS_PER_TEST);
+    vector<Quadripoint> rerandomizations(NUM_RUNS_PER_TEST);
+    
+    system.encrypt(oneEncryption, one);
+
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+    {
+        system.encrypt(firstEncryptions[i], testVals[i]);
+        realEncryptions[i] = system.homomorphic_multiplication(firstEncryptions[i], oneEncryption);
+    }   
+
+    chrono::high_resolution_clock::time_point t0 = chrono::high_resolution_clock::now();
+
+    for (size_t i = 0; i < NUM_RUNS_PER_TEST; i++)
+        rerandomizations[i] = system.rerandomize(realEncryptions[i]);
 
     chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
     chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t1 - t0);
@@ -465,6 +681,54 @@ int main(int argc, char *argv[])
     cout << "test_QuadDecryptSpeed (" << NUM_RUNS_PER_TEST << " runs): ";
     cout << testQuadDecryptSpeed(generator) << " seconds" << endl;
 
+    int max = 10;
+    cout << "test_CurveDecryptSpeed (0 -> " << max << "): ";
+    cout << testCurveDecryptSpeed(max) << " seconds" << endl;
+    max = 20;
+    cout << "test_CurveDecryptSpeed (0 -> " << max << "): ";
+    cout << testCurveDecryptSpeed(max) << " seconds" << endl;
+    max = 30;
+    cout << "test_CurveDecryptSpeed (0 -> " << max << "): ";
+    cout << testCurveDecryptSpeed(max) << " seconds" << endl;
+    max = 40;
+    cout << "test_CurveDecryptSpeed (0 -> " << max << "): ";
+    cout << testCurveDecryptSpeed(max) << " seconds" << endl;
+    max = 50;
+    cout << "test_CurveDecryptSpeed (0 -> " << max << "): ";
+    cout << testCurveDecryptSpeed(max) << " seconds" << endl;
+
+    max = 10;
+    cout << "test_TwistDecryptSpeed (0 -> " << max << "): ";
+    cout << testTwistDecryptSpeed(max) << " seconds" << endl;
+    max = 20;
+    cout << "test_TwistDecryptSpeed (0 -> " << max << "): ";
+    cout << testTwistDecryptSpeed(max) << " seconds" << endl;
+    max = 30;
+    cout << "test_TwistDecryptSpeed (0 -> " << max << "): ";
+    cout << testTwistDecryptSpeed(max) << " seconds" << endl;
+    max = 40;
+    cout << "test_TwistDecryptSpeed (0 -> " << max << "): ";
+    cout << testTwistDecryptSpeed(max) << " seconds" << endl;
+    max = 50;
+    cout << "test_TwistDecryptSpeed (0 -> " << max << "): ";
+    cout << testTwistDecryptSpeed(max) << " seconds" << endl;
+
+    max = 10;
+    cout << "test_QuadDecryptSpeed (0 -> " << max << "): ";
+    cout << testQuadDecryptSpeed(max) << " seconds" << endl;
+    max = 20;
+    cout << "test_QuadDecryptSpeed (0 -> " << max << "): ";
+    cout << testQuadDecryptSpeed(max) << " seconds" << endl;
+    max = 30;
+    cout << "test_QuadDecryptSpeed (0 -> " << max << "): ";
+    cout << testQuadDecryptSpeed(max) << " seconds" << endl;
+    max = 40;
+    cout << "test_QuadDecryptSpeed (0 -> " << max << "): ";
+    cout << testQuadDecryptSpeed(max) << " seconds" << endl;
+    max = 50;
+    cout << "test_QuadDecryptSpeed (0 -> " << max << "): ";
+    cout << testQuadDecryptSpeed(max) << " seconds" << endl;
+
     int addX = distribution(generator);
     int addY = distribution(generator);
     cout << "test_Addition (" << addX << ", " << addY << "): ";
@@ -493,5 +757,21 @@ int main(int argc, char *argv[])
     cout << "test_MultiplicationSpeed (" << NUM_RUNS_PER_TEST << " runs): ";
     cout << testMultiplicationSpeed(generator) << " seconds" << endl;
 
+    int rerandomizingPoint = distribution(generator);
+    cout << "test_Rerandomize (" << rerandomizingPoint << "): ";
+    if (testRerandomize(rerandomizingPoint))
+        cout << "PASS" << endl;
+    else
+        cout << "FAIL" << endl;
+
+    cout << "test_CurveRerandomizeSpeed (" << NUM_RUNS_PER_TEST << " runs): ";
+    cout << testCurveRerandomizeSpeed(generator) << " seconds" << endl;
+
+    cout << "test_TwistRerandomizeSpeed (" << NUM_RUNS_PER_TEST << " runs): ";
+    cout << testTwistRerandomizeSpeed(generator) << " seconds" << endl;
+
+    cout << "test_QuadRerandomizeSpeed (" << NUM_RUNS_PER_TEST << " runs): ";
+    cout << testQuadRerandomizeSpeed(generator) << " seconds" << endl;
+
     return 0;
 }