aboutsummaryrefslogtreecommitdiff
path: root/fcp/secagg/server/secret_sharing_harary_graph_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'fcp/secagg/server/secret_sharing_harary_graph_test.cc')
-rw-r--r--fcp/secagg/server/secret_sharing_harary_graph_test.cc315
1 files changed, 315 insertions, 0 deletions
diff --git a/fcp/secagg/server/secret_sharing_harary_graph_test.cc b/fcp/secagg/server/secret_sharing_harary_graph_test.cc
new file mode 100644
index 0000000..85fd32e
--- /dev/null
+++ b/fcp/secagg/server/secret_sharing_harary_graph_test.cc
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <memory>
+#include <string>
+
+#include "absl/status/status.h"
+#include "fcp/secagg/server/secret_sharing_graph.h"
+#include "fcp/secagg/server/secret_sharing_graph_factory.h"
+#include "fcp/testing/testing.h"
+
+namespace fcp {
+namespace secagg {
+namespace {
+
+namespace secret_sharing_harary_graph_test_internal {
+// Auxiliary function returning the index of j in the list of neighbors of i,
+// in a graph g represented as an adjacency list
+std::optional<int> GetNeighborIndexFromAdjacencyList(
+ const std::vector<std::vector<int>>& g, int i, int j) {
+ auto index = std::find(std::begin(g[i]), std::end(g[i]), j);
+ if (index != std::end(g[i])) {
+ return *index;
+ }
+ return {};
+}
+} // namespace secret_sharing_harary_graph_test_internal
+
+static constexpr int kNumNodes = 10;
+static constexpr int kDegree = 5;
+static constexpr int kThreshold = 2;
+
+TEST(SecretSharingHararyGraphTest, GetPermutationReturnsPermutation) {
+ SecretSharingGraphFactory factory;
+ auto graph = factory.CreateHararyGraph(kNumNodes, kDegree, kThreshold);
+ std::vector<int> permutation = graph->GetPermutationForTesting();
+ EXPECT_EQ(permutation.size(), kNumNodes);
+ std::vector<int> counters(kNumNodes, 0);
+ for (int i = 0; i < permutation.size(); ++i) {
+ counters[permutation[i]]++;
+ }
+ for (auto x : counters) {
+ EXPECT_EQ(x, 1);
+ }
+}
+
+TEST(SecretSharingHararyGraphTest,
+ GetPermutationInDeterministicHararyGraphReturnsIdentityPermutation) {
+ SecretSharingGraphFactory factory;
+ auto graph = factory.CreateHararyGraph(kNumNodes, kDegree, kThreshold, false);
+ std::vector<int> permutation = graph->GetPermutationForTesting();
+ for (int i = 0; i < permutation.size(); ++i) {
+ EXPECT_EQ(permutation[i], i);
+ }
+}
+
+TEST(SecretSharingHararyGraphTest,
+ GetPermutationInRandomHararyGraphDoesNotReturnIdentityPermutation) {
+ SecretSharingGraphFactory factory;
+ // We use a larger number of nodes so that the probability of getting the
+ // identity permutation by change is negligible
+ int larger_num_nodes = 100;
+ auto graph = factory.CreateHararyGraph(larger_num_nodes, kDegree, kThreshold);
+ std::vector<int> permutation = graph->GetPermutationForTesting();
+ // Find j so that permutation[j] != j. This will be the case for most i's (all
+ // but one in expectation), but one is sufficient in this test.
+ bool found = false;
+ for (int i = 0; i < permutation.size(); ++i) {
+ found = found || (i != permutation[i]);
+ }
+ EXPECT_EQ(found, true);
+}
+
+TEST(SecretSharingHararyGraphTest, AreNeighborsIsCorrectInRandomHararyGraph) {
+ SecretSharingGraphFactory factory;
+ auto graph = factory.CreateHararyGraph(kNumNodes, kDegree, kThreshold);
+
+ EXPECT_EQ(graph->GetNumNodes(), kNumNodes);
+ EXPECT_EQ(graph->GetDegree(), kDegree);
+ EXPECT_EQ(graph->GetThreshold(), kThreshold);
+
+ std::vector<int> p = graph->GetPermutationForTesting();
+ std::vector<std::vector<int>> adjacency_list(kNumNodes,
+ std::vector<int>(kDegree));
+ adjacency_list[p[0]] = {p[8], p[9], p[0], p[1], p[2]};
+ adjacency_list[p[1]] = {p[9], p[0], p[1], p[2], p[3]};
+ adjacency_list[p[2]] = {p[0], p[1], p[2], p[3], p[4]};
+ adjacency_list[p[3]] = {p[1], p[2], p[3], p[4], p[5]};
+ adjacency_list[p[4]] = {p[2], p[3], p[4], p[5], p[6]};
+ adjacency_list[p[5]] = {p[3], p[4], p[5], p[6], p[7]};
+ adjacency_list[p[6]] = {p[4], p[5], p[6], p[7], p[8]};
+ adjacency_list[p[7]] = {p[5], p[6], p[7], p[8], p[9]};
+ adjacency_list[p[8]] = {p[6], p[7], p[8], p[9], p[0]};
+ adjacency_list[p[9]] = {p[7], p[8], p[9], p[0], p[1]};
+
+ for (int i = 0; i < kNumNodes; ++i) {
+ for (int j = 0; j < kNumNodes; ++j) {
+ bool are_neighbors =
+ secret_sharing_harary_graph_test_internal::
+ GetNeighborIndexFromAdjacencyList(adjacency_list, i, j)
+ .value_or(-1) >= 0;
+ EXPECT_EQ(graph->AreNeighbors(i, j), are_neighbors) << i << "," << j;
+ }
+ }
+}
+
+TEST(SecretSharingHararyGraphTest,
+ AreNeighborsIsCorrectInDeterministicHararyGraph) {
+ SecretSharingGraphFactory factory;
+ auto graph = factory.CreateHararyGraph(kNumNodes, kDegree, kThreshold, false);
+
+ EXPECT_EQ(graph->GetNumNodes(), kNumNodes);
+ EXPECT_EQ(graph->GetDegree(), kDegree);
+ EXPECT_EQ(graph->GetThreshold(), kThreshold);
+
+ std::vector<int> p = graph->GetPermutationForTesting();
+ std::vector<std::vector<int>> adjacency_list(kNumNodes,
+ std::vector<int>(kDegree));
+ adjacency_list[0] = {8, 9, 0, 1, 2};
+ adjacency_list[1] = {9, 0, 1, 2, 3};
+ adjacency_list[2] = {0, 1, 2, 3, 4};
+ adjacency_list[3] = {1, 2, 3, 4, 5};
+ adjacency_list[4] = {2, 3, 4, 5, 6};
+ adjacency_list[5] = {3, 4, 5, 6, 7};
+ adjacency_list[6] = {4, 5, 6, 7, 8};
+ adjacency_list[7] = {5, 6, 7, 8, 9};
+ adjacency_list[8] = {6, 7, 8, 9, 0};
+ adjacency_list[9] = {7, 8, 9, 0, 1};
+
+ for (int i = 0; i < kNumNodes; ++i) {
+ for (int j = 0; j < kNumNodes; ++j) {
+ bool are_neighbors =
+ secret_sharing_harary_graph_test_internal::
+ GetNeighborIndexFromAdjacencyList(adjacency_list, i, j)
+ .value_or(-1) >= 0;
+ EXPECT_EQ(graph->AreNeighbors(i, j), are_neighbors) << i << "," << j;
+ }
+ }
+}
+
+TEST(SecretSharingHararyGraphTest, GetNeighborsIsCorrectInRandomHararyGraph) {
+ SecretSharingGraphFactory factory;
+ auto graph = factory.CreateHararyGraph(kNumNodes, kDegree, kThreshold);
+
+ EXPECT_EQ(graph->GetNumNodes(), kNumNodes);
+ EXPECT_EQ(graph->GetDegree(), kDegree);
+ EXPECT_EQ(graph->GetThreshold(), kThreshold);
+
+ std::vector<int> p = graph->GetPermutationForTesting();
+ std::vector<std::vector<int>> adjacency_list(kNumNodes,
+ std::vector<int>(kDegree));
+ adjacency_list[p[0]] = {p[8], p[9], p[0], p[1], p[2]};
+ adjacency_list[p[1]] = {p[9], p[0], p[1], p[2], p[3]};
+ adjacency_list[p[2]] = {p[0], p[1], p[2], p[3], p[4]};
+ adjacency_list[p[3]] = {p[1], p[2], p[3], p[4], p[5]};
+ adjacency_list[p[4]] = {p[2], p[3], p[4], p[5], p[6]};
+ adjacency_list[p[5]] = {p[3], p[4], p[5], p[6], p[7]};
+ adjacency_list[p[6]] = {p[4], p[5], p[6], p[7], p[8]};
+ adjacency_list[p[7]] = {p[5], p[6], p[7], p[8], p[9]};
+ adjacency_list[p[8]] = {p[6], p[7], p[8], p[9], p[0]};
+ adjacency_list[p[9]] = {p[7], p[8], p[9], p[0], p[1]};
+
+ for (int i = 0; i < kNumNodes; ++i) {
+ for (int j = 0; j < kDegree; ++j) {
+ auto x = graph->GetNeighbor(i, j);
+ EXPECT_EQ(adjacency_list[i][j], x);
+ }
+ }
+}
+
+TEST(SecretSharingHararyGraphTest,
+ GetNeighborsIsCorrectInDeterministicHararyGraph) {
+ SecretSharingGraphFactory factory;
+ auto graph = factory.CreateHararyGraph(kNumNodes, kDegree, kThreshold, false);
+
+ EXPECT_EQ(graph->GetNumNodes(), kNumNodes);
+ EXPECT_EQ(graph->GetDegree(), kDegree);
+ EXPECT_EQ(graph->GetThreshold(), kThreshold);
+
+ std::vector<int> p = graph->GetPermutationForTesting();
+ std::vector<std::vector<int>> adjacency_list(kNumNodes,
+ std::vector<int>(kDegree));
+ adjacency_list[0] = {8, 9, 0, 1, 2};
+ adjacency_list[1] = {9, 0, 1, 2, 3};
+ adjacency_list[2] = {0, 1, 2, 3, 4};
+ adjacency_list[3] = {1, 2, 3, 4, 5};
+ adjacency_list[4] = {2, 3, 4, 5, 6};
+ adjacency_list[5] = {3, 4, 5, 6, 7};
+ adjacency_list[6] = {4, 5, 6, 7, 8};
+ adjacency_list[7] = {5, 6, 7, 8, 9};
+ adjacency_list[8] = {6, 7, 8, 9, 0};
+ adjacency_list[9] = {7, 8, 9, 0, 1};
+
+ for (int i = 0; i < kNumNodes; ++i) {
+ for (int j = 0; j < kDegree; ++j) {
+ auto x = graph->GetNeighbor(i, j);
+ EXPECT_EQ(adjacency_list[i][j], x);
+ }
+ }
+}
+
+struct HararyGraphParams {
+ const std::string test_name;
+ const int kNumNodes;
+ const int kDegree;
+ const int kThreshold;
+};
+
+class SecretSharingHararyGraphParamTest_Valid
+ : public ::testing::TestWithParam<HararyGraphParams> {};
+
+TEST_P(SecretSharingHararyGraphParamTest_Valid,
+ GetNeighborIndexIsCorrectInHararyGraph) {
+ const HararyGraphParams& graph_params = GetParam();
+ SecretSharingGraphFactory factory;
+ std::unique_ptr<SecretSharingGraph> graph = factory.CreateHararyGraph(
+ graph_params.kNumNodes, graph_params.kDegree, graph_params.kThreshold);
+
+ EXPECT_EQ(graph->GetNumNodes(), graph_params.kNumNodes);
+ EXPECT_EQ(graph->GetDegree(), graph_params.kDegree);
+ EXPECT_EQ(graph->GetThreshold(), graph_params.kThreshold);
+
+ for (int i = 0; i < graph_params.kNumNodes; ++i) {
+ for (int j = 0; j < graph_params.kDegree; ++j) {
+ auto x = graph->GetNeighbor(i, j);
+ EXPECT_EQ(graph->GetNeighborIndex(i, x), j);
+ }
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SecretSharingHararyGraphParamTests, SecretSharingHararyGraphParamTest_Valid,
+ ::testing::ValuesIn<HararyGraphParams>({
+ {"10_nodes__degree_1", 10, 1, 1},
+ {"10_nodes__degree_3", 10, 3, 2},
+ {"10_nodes__degree_5", 10, 5, 3},
+ {"100_nodes__degree_23", 100, 23, 10},
+ {"1000_nodes__degree_43", 1000, 43, 20},
+ {"10000_nodes__degree_300", 10000, 301, 100},
+ }),
+ [](const ::testing::TestParamInfo<
+ SecretSharingHararyGraphParamTest_Valid::ParamType>& info) {
+ return info.param.test_name;
+ });
+
+class SecretSharingHararyGraphParamTest_InvalidDegree
+ : public ::testing::TestWithParam<HararyGraphParams> {};
+
+TEST_P(SecretSharingHararyGraphParamTest_InvalidDegree,
+ ConstructionFailsOnEvenDegree) {
+ const HararyGraphParams& graph_params = GetParam();
+ SecretSharingGraphFactory factory;
+ EXPECT_DEATH(
+ factory.CreateHararyGraph(graph_params.kNumNodes, graph_params.kDegree,
+ graph_params.kThreshold),
+ absl::StrCat("degree must be odd, given value was ",
+ graph_params.kDegree));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SecretSharingHararyGraphParamTests,
+ SecretSharingHararyGraphParamTest_InvalidDegree,
+ ::testing::ValuesIn<HararyGraphParams>({
+ {"10_nodes__degree_4", 10, 4, 2},
+ {"50_nodes__degree_20", 50, 20, 10},
+ }),
+ [](const ::testing::TestParamInfo<
+ SecretSharingHararyGraphParamTest_InvalidDegree::ParamType>& info) {
+ return info.param.test_name;
+ });
+
+class SecretSharingHararyGraphParamTest_InvalidThreshold
+ : public ::testing::TestWithParam<HararyGraphParams> {};
+
+TEST_P(SecretSharingHararyGraphParamTest_InvalidThreshold,
+ ConstructionFailsOnThresholdOutOfObounds) {
+ const HararyGraphParams& graph_params = GetParam();
+ SecretSharingGraphFactory factory;
+ EXPECT_DEATH(
+ factory.CreateHararyGraph(graph_params.kNumNodes, graph_params.kDegree,
+ graph_params.kThreshold),
+ "");
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SecretSharingHararyGraphParamTests,
+ SecretSharingHararyGraphParamTest_InvalidThreshold,
+ ::testing::ValuesIn<HararyGraphParams>({
+ {"10_nodes__degree_4_under", 10, 4, -1},
+ {"10_nodes__degree_4_over", 10, 4, 6},
+ {"50_nodes__degree_20_under", 50, 20, -1},
+ {"50_nodes__degree_20_over", 50, 20, 21},
+ }),
+ [](const ::testing::TestParamInfo<
+ SecretSharingHararyGraphParamTest_InvalidThreshold::ParamType>& info) {
+ return info.param.test_name;
+ });
+
+} // namespace
+} // namespace secagg
+} // namespace fcp