1 /*
2 * (C) 2009 Jack Lloyd
3 *
4 * Botan is released under the Simplified BSD License (see license.txt)
5 */
6 
7 #include "tests.h"
8 
9 #if defined(BOTAN_HAS_THRESHOLD_SECRET_SHARING)
10    #include <botan/tss.h>
11    #include "test_rng.h"
12 #endif
13 
14 namespace Botan_Tests {
15 
16 namespace {
17 
18 #if defined(BOTAN_HAS_THRESHOLD_SECRET_SHARING)
19 
20 class TSS_Recovery_Tests final : public Text_Based_Test
21    {
22    public:
TSS_Recovery_Tests()23       TSS_Recovery_Tests() : Text_Based_Test("tss/recovery.vec", "N,M,Shares,Recovered") {}
24 
run_one_test(const std::string & header,const VarMap & vars)25       Test::Result run_one_test(const std::string& header, const VarMap& vars) override
26          {
27          Test::Result result("TSS");
28 
29          const std::vector<uint8_t> input = vars.get_req_bin("Recovered");
30          const size_t N = vars.get_req_sz("N");
31          const size_t M = vars.get_req_sz("M");
32          const std::vector<std::vector<uint8_t>> expected_shares = vars.get_req_bin_list("Shares");
33 
34          try
35             {
36             std::vector<Botan::RTSS_Share> shares;
37 
38             for(auto&& v : expected_shares)
39                {
40                shares.push_back(Botan::RTSS_Share(v.data(), v.size()));
41                }
42 
43             auto reconstructed_secret_all = Botan::RTSS_Share::reconstruct(shares);
44             result.test_eq("Reconstructed secret correctly from all shares", reconstructed_secret_all, input);
45 
46             if(header == "Invalid")
47                result.test_failure("Invalid shares should not result in recovery");
48 
49             if(N != M)
50                {
51                while(shares.size() > M)
52                   {
53                   size_t to_remove = Test::rng().next_byte() % shares.size();
54                   shares.erase(shares.begin() + to_remove);
55                   try
56                      {
57                      auto reconstructed_secret = Botan::RTSS_Share::reconstruct(shares);
58                      result.test_eq("Reconstructed secret correctly from reduced shares", reconstructed_secret, input);
59                      }
60                   catch(Botan::Decoding_Error&)
61                      {
62                      result.test_failure("Reconstruction failed with share count " + std::to_string(shares.size()));
63                      }
64                   }
65                }
66 
67             }
68          catch(std::exception& e)
69             {
70 
71             if(header == "Valid")
72                result.test_failure("Valid TSS failed to recover", e.what());
73             else
74                result.test_success("Invalid TSS rejected as expected");
75             }
76 
77          return result;
78          }
79    };
80 
81 BOTAN_REGISTER_TEST("utils", "tss_recovery", TSS_Recovery_Tests);
82 
83 class TSS_Generation_Tests final : public Text_Based_Test
84    {
85    public:
TSS_Generation_Tests()86       TSS_Generation_Tests() : Text_Based_Test("tss/generation.vec", "Input,RNG,Hash,Id,N,M,Shares") {}
87 
tss_hash_len(const std::string & hash)88       static size_t tss_hash_len(const std::string& hash)
89          {
90          if(hash == "None")
91             return 0;
92          else if(hash == "SHA-1")
93             return 20;
94          else if(hash == "SHA-256")
95             return 32;
96          else
97             throw Test_Error("Unknown TSS hash algorithm " + hash);
98          }
99 
run_one_test(const std::string &,const VarMap & vars)100       Test::Result run_one_test(const std::string&, const VarMap& vars) override
101          {
102          Test::Result result("TSS");
103 
104          const std::vector<uint8_t> input = vars.get_req_bin("Input");
105          const std::vector<uint8_t> id = vars.get_req_bin("Id");
106          const std::vector<uint8_t> rng_data = vars.get_req_bin("RNG");
107          const uint8_t N = vars.get_req_u8("N");
108          const uint8_t M = vars.get_req_u8("M");
109          const std::string hash = vars.get_req_str("Hash");
110          const std::vector<std::vector<uint8_t>> expected_shares = vars.get_req_bin_list("Shares");
111 
112          if(expected_shares.size() != N)
113             throw Test_Error("Invalid test data for TSS share count != N");
114 
115          if(rng_data.size() != (input.size() + tss_hash_len(hash)) * (M-1))
116             throw Test_Error("Invalid test data for TSS share bad RNG input size");
117 
118          Fixed_Output_RNG fixed_rng(rng_data);
119 
120          std::vector<Botan::RTSS_Share> shares =
121             Botan::RTSS_Share::split(M, N, input.data(), static_cast<uint16_t>(input.size()),
122                                      id, hash, fixed_rng);
123 
124          result.test_eq("Expected number of shares", shares.size(), N);
125 
126          for(size_t i = 0; i != N; ++i)
127             {
128             result.test_eq("Expected share", shares[i].data(), expected_shares[i]);
129             }
130 
131          auto reconstructed_secret_all = Botan::RTSS_Share::reconstruct(shares);
132          result.test_eq("Reconstructed secret correctly from all shares", reconstructed_secret_all, input);
133 
134          if(N != M)
135             {
136             while(shares.size() > M)
137                {
138                size_t to_remove = Test::rng().next_byte() % shares.size();
139                shares.erase(shares.begin() + to_remove);
140 
141                try
142                   {
143                   auto reconstructed_secret = Botan::RTSS_Share::reconstruct(shares);
144                   result.test_eq("Reconstructed secret correctly from reduced shares", reconstructed_secret, input);
145                   }
146                catch(Botan::Decoding_Error&)
147                   {
148                   result.test_failure("Reconstruction failed with share count " + std::to_string(shares.size()));
149                   }
150                }
151             }
152 
153          return result;
154          }
155    };
156 
157 BOTAN_REGISTER_TEST("utils", "tss_generation", TSS_Generation_Tests);
158 
159 #endif // BOTAN_HAS_THRESHOLD_SECRET_SHARING
160 
161 }
162 
163 }
164