@@ -78,6 +78,14 @@ uint8_t gf32_mul(uint8_t x, uint8_t y) {
78
78
return GF32_EXP[(GF32_LOG[x] + GF32_LOG[y]) % 31 ];
79
79
}
80
80
81
+ uint8_t gf32_div (uint8_t x, uint8_t y) {
82
+ assert (y != 0 );
83
+ if (x == 0 ) {
84
+ return 0 ;
85
+ }
86
+ return GF32_EXP[(GF32_LOG[x] + 31 - GF32_LOG[y]) % 31 ];
87
+ }
88
+
81
89
// The bech32 string "secretshare32"
82
90
constexpr const std::array<uint8_t , 13 > CODEX32_M = {
83
91
16 , 25 , 24 , 3 , 25 , 11 , 16 , 23 , 29 , 3 , 25 , 17 , 10
@@ -192,6 +200,24 @@ data CreateChecksum(const std::string& hrp, const data& values, const Residue& g
192
200
return ret;
193
201
}
194
202
203
+ // Given a set of share indices and a target index `idx`, which must be in the set,
204
+ // compute the Lagrange basis polynomial for `idx` evaluated at the point `eval`.
205
+ //
206
+ // All inputs are GF32 elements, rather than array indices or anything else.
207
+ uint8_t lagrange_coefficient (std::vector<uint8_t >& indices, uint8_t idx, uint8_t eval) {
208
+ uint8_t num = 1 ;
209
+ uint8_t den = 1 ;
210
+ for (const auto idx_i : indices) {
211
+ if (idx_i != idx) {
212
+ num = gf32_mul (num, idx_i ^ eval);
213
+ den = gf32_mul (den, idx_i ^ idx);
214
+ }
215
+ }
216
+
217
+ // return num / den
218
+ return gf32_div (num, den);
219
+ }
220
+
195
221
} // namespace
196
222
197
223
/* * Encode a codex32 string. */
@@ -300,6 +326,64 @@ Result::Result(std::string&& hrp, size_t k, const std::string& id, char share_id
300
326
ConvertBits<8 , 5 , true >([&](unsigned char c) { m_data.push_back (c); }, data.begin (), data.end ());
301
327
}
302
328
329
+ Result::Result (const std::vector<Result>& shares, char output_idx) {
330
+ m_valid = OK;
331
+
332
+ int8_t oidx = bech32::internal::CHARSET_REV[(unsigned char ) output_idx];
333
+ if (oidx == -1 ) {
334
+ m_valid = INVALID_SHARE_IDX;
335
+ }
336
+ if (shares.empty ()) {
337
+ m_valid = TOO_FEW_SHARES;
338
+ return ;
339
+ }
340
+ size_t k = shares[0 ].GetK ();
341
+ if (k > shares.size ()) {
342
+ m_valid = TOO_FEW_SHARES;
343
+ }
344
+ if (m_valid != OK) {
345
+ return ;
346
+ }
347
+
348
+ std::vector<uint8_t > indices;
349
+ indices.reserve (shares.size ());
350
+ for (size_t i = 0 ; i < shares.size (); ++i) {
351
+ // Currently the only supported hrp is "ms" so it is impossible to violate this
352
+ assert (shares[0 ].m_hrp == shares[i].m_hrp );
353
+ if (shares[0 ].m_data [0 ] != shares[i].m_data [0 ]) {
354
+ m_valid = MISMATCH_K;
355
+ }
356
+ for (size_t j = 1 ; j < 5 ; ++j) {
357
+ if (shares[0 ].m_data [j] != shares[i].m_data [j]) {
358
+ m_valid = MISMATCH_ID;
359
+ }
360
+ }
361
+ if (shares[i].m_data .size () != shares[0 ].m_data .size ()) {
362
+ m_valid = MISMATCH_LENGTH;
363
+ }
364
+
365
+ indices.push_back (shares[i].m_data [5 ]);
366
+ for (size_t j = i + 1 ; j < shares.size (); ++j) {
367
+ if (shares[i].m_data [5 ] == shares[j].m_data [5 ]) {
368
+ m_valid = DUPLICATE_SHARE;
369
+ }
370
+ }
371
+ }
372
+
373
+ m_hrp = shares[0 ].m_hrp ;
374
+ m_data.reserve (shares[0 ].m_data .size ());
375
+ for (size_t j = 0 ; j < shares[0 ].m_data .size (); ++j) {
376
+ m_data.push_back (0 );
377
+ }
378
+
379
+ for (size_t i = 0 ; i < shares.size (); ++i) {
380
+ uint8_t lagrange_coeff = lagrange_coefficient (indices, shares[i].m_data [5 ], oidx);
381
+ for (size_t j = 0 ; j < m_data.size (); ++j) {
382
+ m_data[j] ^= gf32_mul (lagrange_coeff, shares[i].m_data [j]);
383
+ }
384
+ }
385
+ }
386
+
303
387
std::string Result::GetIdString () const {
304
388
assert (IsValid ());
305
389
0 commit comments