191 {
192 if(shares.size() <= 1) {
193 throw Decoding_Error("Insufficient shares to do TSS reconstruction");
194 }
195
196 for(size_t i = 0; i != shares.size(); ++i) {
197 if(shares[i].
size() < RTSS_HEADER_SIZE + 1) {
198 throw Decoding_Error("Missing or malformed RTSS header");
199 }
200
202 throw Decoding_Error("Invalid (id = 0) RTSS share detected");
203 }
204
205 if(i > 0) {
206 if(shares[i].
size() != shares[0].
size()) {
207 throw Decoding_Error("Different sized RTSS shares detected");
208 }
209
210 if(!
CT::is_equal(shares[0].m_contents.data(), shares[i].m_contents.data(), RTSS_HEADER_SIZE).as_bool()) {
211 throw Decoding_Error("Different RTSS headers detected");
212 }
213 }
214 }
215
216 const uint8_t N = shares[0].m_contents[17];
217
218 if(shares.size() < N) {
219 throw Decoding_Error("Insufficient shares to do TSS reconstruction");
220 }
221
222 const uint16_t share_len =
make_uint16(shares[0].m_contents[18], shares[0].m_contents[19]);
223
224 const uint8_t hash_id = shares[0].m_contents[16];
225 auto hash = get_rtss_hash_by_id(hash_id);
226 const size_t hash_len = (hash ? hash->output_length() : 0);
227
228 if(shares[0].
size() != RTSS_HEADER_SIZE + share_len) {
229
230
231
232
233
234
235 if(shares[0].
size() <= RTSS_HEADER_SIZE + 1 + hash_len) {
236 throw Decoding_Error("Bad RTSS length field in header");
237 }
238 }
239
240 std::vector<uint8_t> V(shares.size());
242
243
244 std::vector<uint8_t> lagrange_coeffs(shares.size());
245 for(size_t k = 0; k != shares.size(); ++k) {
246 uint8_t coeff = 1;
247 for(size_t l = 0; l != shares.size(); ++l) {
248 if(k == l) {
249 continue;
250 }
251 const uint8_t share_k = shares[k].share_id();
252 const uint8_t share_l = shares[l].share_id();
253 if(share_k == share_l) {
254 throw Decoding_Error("Duplicate shares found in RTSS recovery");
255 }
256
258 const uint8_t div = tss_gf_mul(share_l, tss_gf_inv(share_k ^ share_l));
259 coeff = tss_gf_mul(coeff, div);
260 }
261 lagrange_coeffs[k] = coeff;
262 }
263
264 for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i) {
265 for(size_t j = 0; j != V.size(); ++j) {
266 V[j] = shares[j].m_contents[i];
267 }
268
269
270
271
272
273
274
275
276
277 uint8_t r = 0;
278 for(size_t k = 0; k != shares.size(); ++k) {
279 r ^= tss_gf_mul(V[k], lagrange_coeffs[k]);
280 }
281 recovered.push_back(r);
282 }
283
284 if(hash) {
285 if(recovered.size() < hash->output_length()) {
286 throw Decoding_Error("RTSS recovered value too short to be valid");
287 }
288
289 const size_t secret_len = recovered.size() - hash->output_length();
290
291 hash->update(recovered.data(), secret_len);
293
294 if(!
CT::is_equal(hash_check.data(), &recovered[secret_len], hash->output_length()).as_bool()) {
295 throw Decoding_Error("RTSS hash check failed");
296 }
297
298
299 recovered.resize(secret_len);
300 }
301
302 return recovered;
303}
#define BOTAN_ASSERT_NOMSG(expr)
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
std::vector< T, secure_allocator< T > > secure_vector
constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1)