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