1*f0865ec9SKyle Evans /* 2*f0865ec9SKyle Evans * Copyright (C) 2021 - This file is part of libecc project 3*f0865ec9SKyle Evans * 4*f0865ec9SKyle Evans * Authors: 5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com> 6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7*f0865ec9SKyle Evans * 8*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license. 9*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project. 10*f0865ec9SKyle Evans */ 11*f0865ec9SKyle Evans #include "sss_private.h" 12*f0865ec9SKyle Evans #include "sss.h" 13*f0865ec9SKyle Evans 14*f0865ec9SKyle Evans /* 15*f0865ec9SKyle Evans * The purpose of this example is to implement the SSS 16*f0865ec9SKyle Evans * (Shamir's Secret Sharing) scheme based on libecc arithmetic 17*f0865ec9SKyle Evans * primitives. The scheme is implemented over a ~256 bit prime 18*f0865ec9SKyle Evans * field. 19*f0865ec9SKyle Evans * 20*f0865ec9SKyle Evans * Secret sharing allows to combine some shares (at least k among n >= k) 21*f0865ec9SKyle Evans * to regenerate a secret. The current code also ensures the integrity 22*f0865ec9SKyle Evans * of the shares using HMAC. A maximum of (2**16 - 1) shares can be 23*f0865ec9SKyle Evans * generated, and beware that the time complexity of generation heavily 24*f0865ec9SKyle Evans * increases with k and n, and the time complexity of shares combination 25*f0865ec9SKyle Evans * increases with k. 26*f0865ec9SKyle Evans * 27*f0865ec9SKyle Evans * Shares regeneration from exisiting ones is also offered although it 28*f0865ec9SKyle Evans * is expensive in CPU cycles (as the Lagrange interpolation polynomials 29*f0865ec9SKyle Evans * have to be evaluated for each existing share before computing new ones). 30*f0865ec9SKyle Evans * 31*f0865ec9SKyle Evans * !! DISCLAIMER !! 32*f0865ec9SKyle Evans * ================ 33*f0865ec9SKyle Evans * Some efforts have been put on providing a clean code and constant time 34*f0865ec9SKyle Evans * as well as some SCA (side-channel attacks) resistance (e.g. blinding some 35*f0865ec9SKyle Evans * operations manipulating secrets). However, no absolute guarantee can be claimed: 36*f0865ec9SKyle Evans * use this code knowingly and at your own risks! 37*f0865ec9SKyle Evans * 38*f0865ec9SKyle Evans * Also, as for all other libecc primitives, beware of randomness sources. By default, 39*f0865ec9SKyle Evans * the library uses the OS random sources (e.g. "/dev/urandom"), but the user 40*f0865ec9SKyle Evans * is encouraged to adapt the ../external_deps/rand.c source file to combine 41*f0865ec9SKyle Evans * multiple sources and add entropy there depending on the context where this 42*f0865ec9SKyle Evans * code is integrated. The security level of all the cryptographic primitives 43*f0865ec9SKyle Evans * heavily relies on random sources quality. 44*f0865ec9SKyle Evans * 45*f0865ec9SKyle Evans */ 46*f0865ec9SKyle Evans 47*f0865ec9SKyle Evans #ifndef GET_UINT16_BE 48*f0865ec9SKyle Evans #define GET_UINT16_BE(n, b, i) \ 49*f0865ec9SKyle Evans do { \ 50*f0865ec9SKyle Evans (n) = (u16)( ((u16) (b)[(i) ]) << 8 ) \ 51*f0865ec9SKyle Evans | (u16)( ((u16) (b)[(i) + 1]) ); \ 52*f0865ec9SKyle Evans } while( 0 ) 53*f0865ec9SKyle Evans #endif 54*f0865ec9SKyle Evans 55*f0865ec9SKyle Evans #ifndef PUT_UINT16_BE 56*f0865ec9SKyle Evans #define PUT_UINT16_BE(n, b, i) \ 57*f0865ec9SKyle Evans do { \ 58*f0865ec9SKyle Evans (b)[(i) ] = (u8) ( (n) >> 8 ); \ 59*f0865ec9SKyle Evans (b)[(i) + 1] = (u8) ( (n) ); \ 60*f0865ec9SKyle Evans } while( 0 ) 61*f0865ec9SKyle Evans #endif 62*f0865ec9SKyle Evans 63*f0865ec9SKyle Evans /* The prime number we use: it is close to (2**256-1) but still stricly less 64*f0865ec9SKyle Evans * than this value, hence a theoretical security of more than 255 bits but less than 65*f0865ec9SKyle Evans * 256 bits. This prime p is used in the prime field of secp256k1, the "bitcoin" 66*f0865ec9SKyle Evans * curve. 67*f0865ec9SKyle Evans * 68*f0865ec9SKyle Evans * This can be modified with another prime, beware however of the size 69*f0865ec9SKyle Evans * of the prime to be in line with the shared secrets sizes, and also 70*f0865ec9SKyle Evans * that all our shares and secret lie in Fp, and hence are < p, 71*f0865ec9SKyle Evans * 72*f0865ec9SKyle Evans * Although bigger primes could be used, beware that SSS shares recombination 73*f0865ec9SKyle Evans * complexity is quadratic in the number of shares, yielding impractical 74*f0865ec9SKyle Evans * computation time when the prime is too big. Also, some elements related to 75*f0865ec9SKyle Evans * the share generation (_sss_derive_seed) must be adapated to keep proper entropy 76*f0865ec9SKyle Evans * if the prime (size) is modified. 77*f0865ec9SKyle Evans */ 78*f0865ec9SKyle Evans static const u8 prime[] = { 79*f0865ec9SKyle Evans 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 80*f0865ec9SKyle Evans 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 81*f0865ec9SKyle Evans 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 82*f0865ec9SKyle Evans 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 83*f0865ec9SKyle Evans }; 84*f0865ec9SKyle Evans 85*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _sss_derive_seed(fp_t out, const u8 seed[SSS_SECRET_SIZE], u16 idx) 86*f0865ec9SKyle Evans { 87*f0865ec9SKyle Evans int ret; 88*f0865ec9SKyle Evans u8 hmac_val[SHA512_DIGEST_SIZE]; 89*f0865ec9SKyle Evans u8 C[2]; 90*f0865ec9SKyle Evans u8 len; 91*f0865ec9SKyle Evans nn nn_val; 92*f0865ec9SKyle Evans 93*f0865ec9SKyle Evans /* Sanity check on sizes to avoid entropy loss through reduction biases */ 94*f0865ec9SKyle Evans MUST_HAVE((SHA512_DIGEST_SIZE >= (2 * SSS_SECRET_SIZE)), ret, err); 95*f0865ec9SKyle Evans 96*f0865ec9SKyle Evans /* out must be initialized with a context */ 97*f0865ec9SKyle Evans ret = fp_check_initialized(out); EG(ret, err); 98*f0865ec9SKyle Evans 99*f0865ec9SKyle Evans ret = local_memset(hmac_val, 0, sizeof(hmac_val)); EG(ret, err); 100*f0865ec9SKyle Evans ret = local_memset(C, 0, sizeof(C)); EG(ret, err); 101*f0865ec9SKyle Evans 102*f0865ec9SKyle Evans /* Export our idx in big endian representation on two bytes */ 103*f0865ec9SKyle Evans PUT_UINT16_BE(idx, C, 0); 104*f0865ec9SKyle Evans 105*f0865ec9SKyle Evans len = sizeof(hmac_val); 106*f0865ec9SKyle Evans ret = hmac(seed, SSS_SECRET_SIZE, SHA512, C, sizeof(C), hmac_val, &len); EG(ret, err); 107*f0865ec9SKyle Evans 108*f0865ec9SKyle Evans ret = nn_init_from_buf(&nn_val, hmac_val, len); EG(ret, err); 109*f0865ec9SKyle Evans /* Since we will put this in Fp, take the modulo */ 110*f0865ec9SKyle Evans ret = nn_mod(&nn_val, &nn_val, &(out->ctx->p)); EG(ret, err); 111*f0865ec9SKyle Evans /* Now import our reduced value in Fp as the result of the derivation */ 112*f0865ec9SKyle Evans ret = fp_set_nn(out, &nn_val); 113*f0865ec9SKyle Evans 114*f0865ec9SKyle Evans err: 115*f0865ec9SKyle Evans /* Cleanup secret data */ 116*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(hmac_val, 0, sizeof(hmac_val))); 117*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(C, 0, sizeof(C))); 118*f0865ec9SKyle Evans nn_uninit(&nn_val); 119*f0865ec9SKyle Evans 120*f0865ec9SKyle Evans return ret; 121*f0865ec9SKyle Evans } 122*f0865ec9SKyle Evans 123*f0865ec9SKyle Evans /***** Raw versions ***********************/ 124*f0865ec9SKyle Evans /* SSS shares and secret generation */ 125*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _sss_raw_generate(sss_share *shares, u16 k, u16 n, sss_secret *secret, boolean input_secret) 126*f0865ec9SKyle Evans { 127*f0865ec9SKyle Evans fp_ctx ctx; 128*f0865ec9SKyle Evans nn p; 129*f0865ec9SKyle Evans fp a0, a, s; 130*f0865ec9SKyle Evans fp exp, base, tmp; 131*f0865ec9SKyle Evans fp blind, blind_inv; 132*f0865ec9SKyle Evans u8 secret_seed[SSS_SECRET_SIZE]; 133*f0865ec9SKyle Evans u16 idx_shift, num_shares; 134*f0865ec9SKyle Evans int ret; 135*f0865ec9SKyle Evans unsigned int i, j; 136*f0865ec9SKyle Evans p.magic = WORD(0); 137*f0865ec9SKyle Evans exp.magic = base.magic = tmp.magic = s.magic = a.magic = a0.magic = WORD(0); 138*f0865ec9SKyle Evans blind.magic = blind_inv.magic = WORD(0); 139*f0865ec9SKyle Evans 140*f0865ec9SKyle Evans ret = local_memset(secret_seed, 0, sizeof(secret_seed)); EG(ret, err); 141*f0865ec9SKyle Evans 142*f0865ec9SKyle Evans MUST_HAVE((shares != NULL) && (secret != NULL), ret, err); 143*f0865ec9SKyle Evans /* Sanity checks */ 144*f0865ec9SKyle Evans MUST_HAVE((n <= (u16)(0xffff - 1)), ret, err); 145*f0865ec9SKyle Evans MUST_HAVE((k <= n), ret, err); 146*f0865ec9SKyle Evans MUST_HAVE((k >= 1), ret, err); 147*f0865ec9SKyle Evans MUST_HAVE((SSS_SECRET_SIZE == sizeof(prime)), ret, err); 148*f0865ec9SKyle Evans 149*f0865ec9SKyle Evans /* Import our prime number and create the Fp context */ 150*f0865ec9SKyle Evans ret = nn_init_from_buf(&p, prime, sizeof(prime)); EG(ret, err); 151*f0865ec9SKyle Evans ret = fp_ctx_init_from_p(&ctx, &p); EG(ret, err); 152*f0865ec9SKyle Evans 153*f0865ec9SKyle Evans /* Generate a secret seed of the size of the secret that will be our base to 154*f0865ec9SKyle Evans * generate the plolynomial coefficients. 155*f0865ec9SKyle Evans */ 156*f0865ec9SKyle Evans ret = get_random(secret_seed, sizeof(secret_seed)); EG(ret, err); 157*f0865ec9SKyle Evans /* NOTE: although we could generate all our a[i] coefficients using our randomness 158*f0865ec9SKyle Evans * source, we prefer to derive them from a single secret seed in order to optimize 159*f0865ec9SKyle Evans * the storage space as our share generation algorithm needs to parse these a[i] multiple 160*f0865ec9SKyle Evans * times. This time / memory tradeoff saves a lot of memory space for embedded contexts and 161*f0865ec9SKyle Evans * avoids "malloc" usage (preserving the "no dynamic allocation" philosophy of libecc). 162*f0865ec9SKyle Evans * 163*f0865ec9SKyle Evans * Our secret seed is SSS_SECRET_SIZE long, so on the security side there should be no 164*f0865ec9SKyle Evans * loss of strength/entropy. For each index i, a[i] is computed as follows: 165*f0865ec9SKyle Evans * 166*f0865ec9SKyle Evans * a[i] = HMAC(secret_seed, i) 167*f0865ec9SKyle Evans * where the HMAC is interpreted as a value in Fp (i.e. modulo p), and i is represented 168*f0865ec9SKyle Evans * as a string of 2 elements. The HMAC uses a hash function of at least twice the 169*f0865ec9SKyle Evans * size of the secret to avoid biases in modular reduction. 170*f0865ec9SKyle Evans */ 171*f0865ec9SKyle Evans 172*f0865ec9SKyle Evans /* a0 is either derived from the secret seed or taken from input if 173*f0865ec9SKyle Evans * provided. 174*f0865ec9SKyle Evans */ 175*f0865ec9SKyle Evans ret = fp_init(&a0, &ctx); EG(ret, err); 176*f0865ec9SKyle Evans if(input_secret == SSS_TRUE){ 177*f0865ec9SKyle Evans /* Import the secret the user provides 178*f0865ec9SKyle Evans * XXX: NOTE: the user shared secret MUST be in Fp! Since our prime is < (2**256 - 1), 179*f0865ec9SKyle Evans * some 256 bit strings can be rejected here (namely those >= p and <= (2**256 - 1)). 180*f0865ec9SKyle Evans */ 181*f0865ec9SKyle Evans ret = fp_import_from_buf(&a0, secret->secret, SSS_SECRET_SIZE); EG(ret, err); 182*f0865ec9SKyle Evans } 183*f0865ec9SKyle Evans else{ 184*f0865ec9SKyle Evans /* Generate the secret from our seed */ 185*f0865ec9SKyle Evans ret = _sss_derive_seed(&a0, secret_seed, 0); EG(ret, err); 186*f0865ec9SKyle Evans } 187*f0865ec9SKyle Evans 188*f0865ec9SKyle Evans /* Compute the shares P(x) for x in [idx_shift + 0, ..., idx_shift + n] (or 189*f0865ec9SKyle Evans * [idx_shift + 0, ..., idx_shift + n + 1] to avoid the 0 index), 190*f0865ec9SKyle Evans * with idx_shift a non-zero random index shift to avoid leaking the number of shares. 191*f0865ec9SKyle Evans */ 192*f0865ec9SKyle Evans ret = fp_init(&base, &ctx); EG(ret, err); 193*f0865ec9SKyle Evans ret = fp_init(&exp, &ctx); EG(ret, err); 194*f0865ec9SKyle Evans ret = fp_init(&tmp, &ctx); EG(ret, err); 195*f0865ec9SKyle Evans ret = fp_init(&s, &ctx); EG(ret, err); 196*f0865ec9SKyle Evans ret = fp_init(&a, &ctx); EG(ret, err); 197*f0865ec9SKyle Evans /* Get a random blind mask and invert it */ 198*f0865ec9SKyle Evans ret = fp_get_random(&blind, &ctx); EG(ret, err); 199*f0865ec9SKyle Evans ret = fp_init(&blind_inv, &ctx); EG(ret, err); 200*f0865ec9SKyle Evans ret = fp_inv(&blind_inv, &blind); EG(ret, err); 201*f0865ec9SKyle Evans /* Generate a non-zero random index base for x to avoid leaking 202*f0865ec9SKyle Evans * the number of shares. We could use a static sequence from x = 1 to n 203*f0865ec9SKyle Evans * but this would leak some information to the participants about the number 204*f0865ec9SKyle Evans * of shares (e.g. if a participant gets the share with x = 4, she surely knows 205*f0865ec9SKyle Evans * that n >= 4). To avoid the leak we randomize the base value of the index where 206*f0865ec9SKyle Evans * we begin our x. 207*f0865ec9SKyle Evans */ 208*f0865ec9SKyle Evans idx_shift = 0; 209*f0865ec9SKyle Evans while(idx_shift == 0){ 210*f0865ec9SKyle Evans ret = get_random((u8*)&idx_shift, sizeof(idx_shift)); EG(ret, err); 211*f0865ec9SKyle Evans } 212*f0865ec9SKyle Evans num_shares = 0; 213*f0865ec9SKyle Evans i = 0; 214*f0865ec9SKyle Evans while(num_shares < n){ 215*f0865ec9SKyle Evans _sss_raw_share *cur_share_i = &(shares[num_shares].raw_share); 216*f0865ec9SKyle Evans u16 curr_idx = (u16)(idx_shift + i); 217*f0865ec9SKyle Evans if(curr_idx == 0){ 218*f0865ec9SKyle Evans /* Skip the index 0 specific case */ 219*f0865ec9SKyle Evans i++; 220*f0865ec9SKyle Evans continue; 221*f0865ec9SKyle Evans } 222*f0865ec9SKyle Evans /* Set s[i] to the a[0] as blinded initial value */ 223*f0865ec9SKyle Evans ret = fp_mul(&s, &blind, &a0); EG(ret, err); 224*f0865ec9SKyle Evans /* Get a random base x as u16 for share index */ 225*f0865ec9SKyle Evans ret = fp_set_word_value(&base, (word_t)curr_idx); EG(ret, err); 226*f0865ec9SKyle Evans /* Set the exp to 1 */ 227*f0865ec9SKyle Evans ret = fp_one(&exp); EG(ret, err); 228*f0865ec9SKyle Evans for(j = 1; j < k; j++){ 229*f0865ec9SKyle Evans /* Compute x**j by iterative multiplications */ 230*f0865ec9SKyle Evans ret = fp_mul_monty(&exp, &exp, &base); EG(ret, err); 231*f0865ec9SKyle Evans /* Compute our a[j] coefficient */ 232*f0865ec9SKyle Evans ret = _sss_derive_seed(&a, secret_seed, (u16)j); EG(ret, err); 233*f0865ec9SKyle Evans /* Blind a[j] */ 234*f0865ec9SKyle Evans ret = fp_mul_monty(&a, &a, &blind); EG(ret, err); 235*f0865ec9SKyle Evans /* NOTE1: actually, the real a[j] coefficients are _sss_derive_seed(secret_seed, j) 236*f0865ec9SKyle Evans * multiplied by some power of r^-1 (the Montgomery constant), but this is OK as 237*f0865ec9SKyle Evans * we need any random values (computable from the secret seed) here. We use this "trick" 238*f0865ec9SKyle Evans * to be able to use our more performant redcified versions of Fp multiplication. 239*f0865ec9SKyle Evans * 240*f0865ec9SKyle Evans * NOTE2: this trick makes also this generation not deterministic with the same seed 241*f0865ec9SKyle Evans * on binaries with different WORD sizes (16, 32, 64 bits) as the r Montgomery constant will 242*f0865ec9SKyle Evans * differ depending on this size. However, this is not really an issue per se for our SSS 243*f0865ec9SKyle Evans * as we are in our generation primitive and the a[j] coefficients are expected to be 244*f0865ec9SKyle Evans * random (the only drawback is that deterministic test vectors will not be consistent 245*f0865ec9SKyle Evans * across WORD sizes). 246*f0865ec9SKyle Evans */ 247*f0865ec9SKyle Evans /* Accumulate */ 248*f0865ec9SKyle Evans ret = fp_mul_monty(&tmp, &exp, &a); EG(ret, err); 249*f0865ec9SKyle Evans ret = fp_add(&s, &s, &tmp); EG(ret, err); 250*f0865ec9SKyle Evans } 251*f0865ec9SKyle Evans /* Export the computed share */ 252*f0865ec9SKyle Evans PUT_UINT16_BE(curr_idx, (u8*)&(cur_share_i->index), 0); 253*f0865ec9SKyle Evans /* Unblind */ 254*f0865ec9SKyle Evans ret = fp_mul(&s, &s, &blind_inv); EG(ret, err); 255*f0865ec9SKyle Evans ret = fp_export_to_buf(cur_share_i->share, SSS_SECRET_SIZE, &s); EG(ret, err); 256*f0865ec9SKyle Evans num_shares++; 257*f0865ec9SKyle Evans i++; 258*f0865ec9SKyle Evans } 259*f0865ec9SKyle Evans /* The secret is a[0] */ 260*f0865ec9SKyle Evans ret = fp_export_to_buf(secret->secret, SSS_SECRET_SIZE, &a0); 261*f0865ec9SKyle Evans 262*f0865ec9SKyle Evans err: 263*f0865ec9SKyle Evans /* We can throw away our secret seed now that the shares have 264*f0865ec9SKyle Evans * been generated. 265*f0865ec9SKyle Evans */ 266*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(secret_seed, 0, sizeof(secret_seed))); 267*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(&ctx, 0, sizeof(ctx))); 268*f0865ec9SKyle Evans nn_uninit(&p); 269*f0865ec9SKyle Evans fp_uninit(&a0); 270*f0865ec9SKyle Evans fp_uninit(&a); 271*f0865ec9SKyle Evans fp_uninit(&s); 272*f0865ec9SKyle Evans fp_uninit(&base); 273*f0865ec9SKyle Evans fp_uninit(&exp); 274*f0865ec9SKyle Evans fp_uninit(&tmp); 275*f0865ec9SKyle Evans fp_uninit(&blind); 276*f0865ec9SKyle Evans fp_uninit(&blind_inv); 277*f0865ec9SKyle Evans 278*f0865ec9SKyle Evans return ret; 279*f0865ec9SKyle Evans } 280*f0865ec9SKyle Evans 281*f0865ec9SKyle Evans /* SSS helper to compute Lagrange interpolation on an input value. 282*f0865ec9SKyle Evans * - k is the number of shares pointed by the shares pointer 283*f0865ec9SKyle Evans * - secret is the computed secret 284*f0865ec9SKyle Evans * - val is the 'index' on which the Lagrange interpolation must be computed, i.e. 285*f0865ec9SKyle Evans * the idea is to have using Lagrage formulas the value f(val) where f is our polynomial. Of course 286*f0865ec9SKyle Evans * the proper value can only be computed if enough shares k are provided (the interpolation 287*f0865ec9SKyle Evans * does not hold in other cases and the result will be an incorrect value) 288*f0865ec9SKyle Evans */ 289*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _sss_raw_lagrange(const sss_share *shares, u16 k, sss_secret *secret, u16 val) 290*f0865ec9SKyle Evans { 291*f0865ec9SKyle Evans fp_ctx ctx; 292*f0865ec9SKyle Evans nn p; 293*f0865ec9SKyle Evans fp s, x, y; 294*f0865ec9SKyle Evans fp x_i, x_j, tmp, tmp2; 295*f0865ec9SKyle Evans fp blind, blind_inv, r_inv; 296*f0865ec9SKyle Evans int ret; 297*f0865ec9SKyle Evans unsigned int i, j; 298*f0865ec9SKyle Evans p.magic = WORD(0); 299*f0865ec9SKyle Evans x_i.magic = x_j.magic = tmp.magic = tmp2.magic = s.magic = y.magic = x.magic = WORD(0); 300*f0865ec9SKyle Evans blind.magic = blind_inv.magic = r_inv.magic = WORD(0); 301*f0865ec9SKyle Evans 302*f0865ec9SKyle Evans MUST_HAVE((shares != NULL) && (secret != NULL), ret, err); 303*f0865ec9SKyle Evans /* Sanity checks */ 304*f0865ec9SKyle Evans MUST_HAVE((k >= 1), ret, err); 305*f0865ec9SKyle Evans MUST_HAVE((SSS_SECRET_SIZE == sizeof(prime)), ret, err); 306*f0865ec9SKyle Evans 307*f0865ec9SKyle Evans /* Import our prime number and create the Fp context */ 308*f0865ec9SKyle Evans ret = nn_init_from_buf(&p, prime, sizeof(prime)); EG(ret, err); 309*f0865ec9SKyle Evans ret = fp_ctx_init_from_p(&ctx, &p); EG(ret, err); 310*f0865ec9SKyle Evans 311*f0865ec9SKyle Evans /* Recombine our shared secrets */ 312*f0865ec9SKyle Evans ret = fp_init(&s, &ctx); EG(ret, err); 313*f0865ec9SKyle Evans ret = fp_init(&y, &ctx); EG(ret, err); 314*f0865ec9SKyle Evans ret = fp_init(&x_i, &ctx); EG(ret, err); 315*f0865ec9SKyle Evans ret = fp_init(&x_j, &ctx); EG(ret, err); 316*f0865ec9SKyle Evans ret = fp_init(&tmp, &ctx); EG(ret, err); 317*f0865ec9SKyle Evans ret = fp_init(&tmp2, &ctx); EG(ret, err); 318*f0865ec9SKyle Evans if(val != 0){ 319*f0865ec9SKyle Evans /* NOTE: we treat the case 'val = 0' in a specific case for 320*f0865ec9SKyle Evans * optimization. This optimization is of interest since computing 321*f0865ec9SKyle Evans * f(0) (where f(.) is our polynomial) is the formula for getting the 322*f0865ec9SKyle Evans * SSS secret (which happens to be the constant of degree 0 of the 323*f0865ec9SKyle Evans * polynomial). 324*f0865ec9SKyle Evans */ 325*f0865ec9SKyle Evans ret = fp_init(&x, &ctx); EG(ret, err); 326*f0865ec9SKyle Evans ret = fp_set_word_value(&x, (word_t)val); EG(ret, err); 327*f0865ec9SKyle Evans } 328*f0865ec9SKyle Evans /* Get a random blind mask and invert it */ 329*f0865ec9SKyle Evans ret = fp_get_random(&blind, &ctx); EG(ret, err); 330*f0865ec9SKyle Evans ret = fp_init(&blind_inv, &ctx); EG(ret, err); 331*f0865ec9SKyle Evans ret = fp_inv(&blind_inv, &blind); EG(ret, err); 332*f0865ec9SKyle Evans /* Perform the computation of r^-1 to optimize our multiplications using Montgomery 333*f0865ec9SKyle Evans * multiplication in the main loop. 334*f0865ec9SKyle Evans */ 335*f0865ec9SKyle Evans ret = fp_init(&r_inv, &ctx); EG(ret, err); 336*f0865ec9SKyle Evans ret = fp_set_nn(&r_inv, &(ctx.r)); EG(ret, err); 337*f0865ec9SKyle Evans ret = fp_inv(&r_inv, &r_inv); EG(ret, err); 338*f0865ec9SKyle Evans /* Proceed with the interpolation */ 339*f0865ec9SKyle Evans for(i = 0; i < k; i++){ 340*f0865ec9SKyle Evans u16 curr_idx; 341*f0865ec9SKyle Evans const _sss_raw_share *cur_share_i = &(shares[i].raw_share); 342*f0865ec9SKyle Evans /* Import s[i] */ 343*f0865ec9SKyle Evans ret = fp_import_from_buf(&s, cur_share_i->share, SSS_SECRET_SIZE); EG(ret, err); 344*f0865ec9SKyle Evans /* Blind s[i] */ 345*f0865ec9SKyle Evans ret = fp_mul_monty(&s, &s, &blind); EG(ret, err); 346*f0865ec9SKyle Evans /* Get the index */ 347*f0865ec9SKyle Evans GET_UINT16_BE(curr_idx, (const u8*)&(cur_share_i->index), 0); 348*f0865ec9SKyle Evans ret = fp_set_word_value(&x_i, (word_t)(curr_idx)); EG(ret, err); 349*f0865ec9SKyle Evans /* Initialize multiplication with "one" (actually Montgomery r^-1 for multiplication optimization) */ 350*f0865ec9SKyle Evans ret = fp_copy(&tmp2, &r_inv); EG(ret, err); 351*f0865ec9SKyle Evans /* Compute the product for all k other than i 352*f0865ec9SKyle Evans * NOTE: we use fp_mul in its redcified version as the multiplication by r^-1 is 353*f0865ec9SKyle Evans * cancelled by the fraction of (x_j - x) * r^-1 / (x_j - x_i) * r^-1 = (x_j - x) / (x_j - x_i) 354*f0865ec9SKyle Evans */ 355*f0865ec9SKyle Evans for(j = 0; j < k; j++){ 356*f0865ec9SKyle Evans const _sss_raw_share *cur_share_j = &(shares[j].raw_share); 357*f0865ec9SKyle Evans GET_UINT16_BE(curr_idx, (const u8*)&(cur_share_j->index), 0); 358*f0865ec9SKyle Evans ret = fp_set_word_value(&x_j, (word_t)(curr_idx)); EG(ret, err); 359*f0865ec9SKyle Evans if(j != i){ 360*f0865ec9SKyle Evans if(val != 0){ 361*f0865ec9SKyle Evans ret = fp_sub(&tmp, &x_j, &x); EG(ret, err); 362*f0865ec9SKyle Evans ret = fp_mul_monty(&s, &s, &tmp); EG(ret, err); 363*f0865ec9SKyle Evans } 364*f0865ec9SKyle Evans else{ 365*f0865ec9SKyle Evans /* NOTE: we treat the case 'val = 0' in a specific case for 366*f0865ec9SKyle Evans * optimization. This optimization is of interest since computing 367*f0865ec9SKyle Evans * f(0) (where f(.) is our polynomial) is the formula for getting the 368*f0865ec9SKyle Evans * SSS secret (which happens to be the constant of degree 0 of the 369*f0865ec9SKyle Evans * polynomial). 370*f0865ec9SKyle Evans */ 371*f0865ec9SKyle Evans ret = fp_mul_monty(&s, &s, &x_j); EG(ret, err); 372*f0865ec9SKyle Evans } 373*f0865ec9SKyle Evans ret = fp_sub(&tmp, &x_j, &x_i); EG(ret, err); 374*f0865ec9SKyle Evans ret = fp_mul_monty(&tmp2, &tmp2, &tmp); EG(ret, err); 375*f0865ec9SKyle Evans } 376*f0865ec9SKyle Evans } 377*f0865ec9SKyle Evans /* Invert all the (x_j - x_i) poducts */ 378*f0865ec9SKyle Evans ret = fp_inv(&tmp, &tmp2); EG(ret, err); 379*f0865ec9SKyle Evans ret = fp_mul_monty(&s, &s, &tmp); EG(ret, err); 380*f0865ec9SKyle Evans /* Accumulate in secret */ 381*f0865ec9SKyle Evans ret = fp_add(&y, &y, &s); EG(ret, err); 382*f0865ec9SKyle Evans } 383*f0865ec9SKyle Evans /* Unblind y */ 384*f0865ec9SKyle Evans ret = fp_redcify(&y, &y); EG(ret, err); 385*f0865ec9SKyle Evans ret = fp_mul(&y, &y, &blind_inv); EG(ret, err); 386*f0865ec9SKyle Evans /* We should have our secret in y */ 387*f0865ec9SKyle Evans ret = fp_export_to_buf(secret->secret, SSS_SECRET_SIZE, &y); 388*f0865ec9SKyle Evans 389*f0865ec9SKyle Evans err: 390*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(&ctx, 0, sizeof(ctx))); 391*f0865ec9SKyle Evans nn_uninit(&p); 392*f0865ec9SKyle Evans fp_uninit(&s); 393*f0865ec9SKyle Evans fp_uninit(&y); 394*f0865ec9SKyle Evans fp_uninit(&x_i); 395*f0865ec9SKyle Evans fp_uninit(&x_j); 396*f0865ec9SKyle Evans fp_uninit(&tmp); 397*f0865ec9SKyle Evans fp_uninit(&tmp2); 398*f0865ec9SKyle Evans fp_uninit(&blind); 399*f0865ec9SKyle Evans fp_uninit(&blind_inv); 400*f0865ec9SKyle Evans fp_uninit(&r_inv); 401*f0865ec9SKyle Evans if(val != 0){ 402*f0865ec9SKyle Evans fp_uninit(&x); 403*f0865ec9SKyle Evans } 404*f0865ec9SKyle Evans 405*f0865ec9SKyle Evans return ret; 406*f0865ec9SKyle Evans } 407*f0865ec9SKyle Evans 408*f0865ec9SKyle Evans 409*f0865ec9SKyle Evans /* SSS shares and secret combination */ 410*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _sss_raw_combine(const sss_share *shares, u16 k, sss_secret *secret) 411*f0865ec9SKyle Evans { 412*f0865ec9SKyle Evans return _sss_raw_lagrange(shares, k, secret, 0); 413*f0865ec9SKyle Evans } 414*f0865ec9SKyle Evans 415*f0865ec9SKyle Evans /***** Secure versions (public APIs) ***********************/ 416*f0865ec9SKyle Evans /* SSS shares and secret generation: 417*f0865ec9SKyle Evans * Inputs: 418*f0865ec9SKyle Evans * - n: is the number of shares to generate 419*f0865ec9SKyle Evans * - k: the quorum of shares to regenerate the secret (of course k <= n) 420*f0865ec9SKyle Evans * - secret: the secret value when input_secret is set to 'true' 421*f0865ec9SKyle Evans * Output: 422*f0865ec9SKyle Evans * - shares: a pointer to the generated n shares 423*f0865ec9SKyle Evans * - secret: the secret value when input_secret is set to 'false', this 424*f0865ec9SKyle Evans * value being randomly generated 425*f0865ec9SKyle Evans */ 426*f0865ec9SKyle Evans int sss_generate(sss_share *shares, unsigned short k, unsigned short n, sss_secret *secret, boolean input_secret) 427*f0865ec9SKyle Evans { 428*f0865ec9SKyle Evans int ret; 429*f0865ec9SKyle Evans unsigned int i; 430*f0865ec9SKyle Evans u8 len; 431*f0865ec9SKyle Evans u8 session_id[SSS_SESSION_ID_SIZE]; 432*f0865ec9SKyle Evans 433*f0865ec9SKyle Evans ret = local_memset(session_id, 0, sizeof(session_id)); EG(ret, err); 434*f0865ec9SKyle Evans 435*f0865ec9SKyle Evans /* Generate raw shares */ 436*f0865ec9SKyle Evans ret = _sss_raw_generate(shares, k, n, secret, input_secret); EG(ret, err); 437*f0865ec9SKyle Evans 438*f0865ec9SKyle Evans /* Sanity check */ 439*f0865ec9SKyle Evans MUST_HAVE((SSS_HMAC_SIZE == sizeof(shares[0].raw_share_hmac)), ret, err); 440*f0865ec9SKyle Evans MUST_HAVE((SHA256_DIGEST_SIZE >= sizeof(shares[0].raw_share_hmac)), ret, err); 441*f0865ec9SKyle Evans 442*f0865ec9SKyle Evans /* Generate a random session ID */ 443*f0865ec9SKyle Evans ret = get_random(session_id, sizeof(session_id)); EG(ret, err); 444*f0865ec9SKyle Evans 445*f0865ec9SKyle Evans /* Compute the authenticity seal for each share with HMAC */ 446*f0865ec9SKyle Evans for(i = 0; i < n; i++){ 447*f0865ec9SKyle Evans _sss_raw_share *cur_share = &(shares[i].raw_share); 448*f0865ec9SKyle Evans u8 *cur_id = (u8*)&(shares[i].session_id); 449*f0865ec9SKyle Evans u8 *cur_share_hmac = (u8*)&(shares[i].raw_share_hmac); 450*f0865ec9SKyle Evans /* NOTE: we 'abuse' casts here for shares[i].raw_share to u8*, but this should be OK since 451*f0865ec9SKyle Evans * our structures are packed. 452*f0865ec9SKyle Evans */ 453*f0865ec9SKyle Evans const u8 *inputs[3] = { (const u8*)cur_share, cur_id, NULL }; 454*f0865ec9SKyle Evans const u32 ilens[3] = { sizeof(*cur_share), SSS_SESSION_ID_SIZE, 0 }; 455*f0865ec9SKyle Evans 456*f0865ec9SKyle Evans /* Copy the session ID */ 457*f0865ec9SKyle Evans ret = local_memcpy(cur_id, session_id, SSS_SESSION_ID_SIZE); EG(ret, err); 458*f0865ec9SKyle Evans 459*f0865ec9SKyle Evans len = SSS_HMAC_SIZE; 460*f0865ec9SKyle Evans ret = hmac_scattered((const u8*)secret, SSS_SECRET_SIZE, SHA256, inputs, ilens, cur_share_hmac, &len); EG(ret, err); 461*f0865ec9SKyle Evans } 462*f0865ec9SKyle Evans 463*f0865ec9SKyle Evans err: 464*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(session_id, 0, sizeof(session_id))); 465*f0865ec9SKyle Evans 466*f0865ec9SKyle Evans return ret; 467*f0865ec9SKyle Evans } 468*f0865ec9SKyle Evans 469*f0865ec9SKyle Evans /* SSS shares and secret combination 470*f0865ec9SKyle Evans * Inputs: 471*f0865ec9SKyle Evans * - k: the quorum of shares to regenerate the secret 472*f0865ec9SKyle Evans * - shares: a pointer to the k shares 473*f0865ec9SKyle Evans * Output: 474*f0865ec9SKyle Evans * - secret: the secret value computed from the k shares 475*f0865ec9SKyle Evans */ 476*f0865ec9SKyle Evans int sss_combine(const sss_share *shares, unsigned short k, sss_secret *secret) 477*f0865ec9SKyle Evans { 478*f0865ec9SKyle Evans int ret, cmp; 479*f0865ec9SKyle Evans unsigned int i; 480*f0865ec9SKyle Evans u8 hmac_val[SSS_HMAC_SIZE]; 481*f0865ec9SKyle Evans u8 len; 482*f0865ec9SKyle Evans 483*f0865ec9SKyle Evans ret = local_memset(hmac_val, 0, sizeof(hmac_val)); EG(ret, err); 484*f0865ec9SKyle Evans 485*f0865ec9SKyle Evans /* Recombine raw shares */ 486*f0865ec9SKyle Evans ret = _sss_raw_combine(shares, k, secret); EG(ret, err); 487*f0865ec9SKyle Evans 488*f0865ec9SKyle Evans /* Compute and check the authenticity seal for each HMAC */ 489*f0865ec9SKyle Evans for(i = 0; i < k; i++){ 490*f0865ec9SKyle Evans const _sss_raw_share *cur_share = &(shares[i].raw_share); 491*f0865ec9SKyle Evans const u8 *cur_id = (const u8*)&(shares[i].session_id); 492*f0865ec9SKyle Evans const u8 *cur_id0 = (const u8*)&(shares[0].session_id); 493*f0865ec9SKyle Evans const u8 *cur_share_hmac = (const u8*)&(shares[i].raw_share_hmac); 494*f0865ec9SKyle Evans /* NOTE: we 'abuse' casts here for shares[i].raw_share to u8*, but this should be OK since 495*f0865ec9SKyle Evans * our structures are packed. 496*f0865ec9SKyle Evans */ 497*f0865ec9SKyle Evans const u8 *inputs[3] = { (const u8*)cur_share, cur_id, NULL }; 498*f0865ec9SKyle Evans const u32 ilens[3] = { sizeof(*cur_share), SSS_SESSION_ID_SIZE, 0 }; 499*f0865ec9SKyle Evans 500*f0865ec9SKyle Evans /* Check that all our shares have the same session ID, return an error otherwise */ 501*f0865ec9SKyle Evans ret = are_equal(cur_id, cur_id0, SSS_SESSION_ID_SIZE, &cmp); EG(ret, err); 502*f0865ec9SKyle Evans if(!cmp){ 503*f0865ec9SKyle Evans #ifdef VERBOSE 504*f0865ec9SKyle Evans ext_printf("[-] sss_combine error for share %d / %d: session ID is not OK!\n", i, k); 505*f0865ec9SKyle Evans #endif 506*f0865ec9SKyle Evans ret = -1; 507*f0865ec9SKyle Evans goto err; 508*f0865ec9SKyle Evans } 509*f0865ec9SKyle Evans 510*f0865ec9SKyle Evans len = sizeof(hmac_val); 511*f0865ec9SKyle Evans ret = hmac_scattered((const u8*)secret, SSS_SECRET_SIZE, SHA256, inputs, ilens, hmac_val, &len); EG(ret, err); 512*f0865ec9SKyle Evans 513*f0865ec9SKyle Evans /* Check the HMAC */ 514*f0865ec9SKyle Evans ret = are_equal(hmac_val, cur_share_hmac, len, &cmp); EG(ret, err); 515*f0865ec9SKyle Evans if(!cmp){ 516*f0865ec9SKyle Evans #ifdef VERBOSE 517*f0865ec9SKyle Evans ext_printf("[-] sss_combine error for share %d / %d: HMAC is not OK!\n", i, k); 518*f0865ec9SKyle Evans #endif 519*f0865ec9SKyle Evans ret = -1; 520*f0865ec9SKyle Evans goto err; 521*f0865ec9SKyle Evans } 522*f0865ec9SKyle Evans } 523*f0865ec9SKyle Evans 524*f0865ec9SKyle Evans err: 525*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(hmac_val, 0, sizeof(hmac_val))); 526*f0865ec9SKyle Evans 527*f0865ec9SKyle Evans return ret; 528*f0865ec9SKyle Evans } 529*f0865ec9SKyle Evans 530*f0865ec9SKyle Evans /* SSS shares regeneration from existing shares 531*f0865ec9SKyle Evans * Inputs: 532*f0865ec9SKyle Evans * - shares: a pointer to the input k shares allowing the regeneration 533*f0865ec9SKyle Evans * - n: is the number of shares to regenerate 534*f0865ec9SKyle Evans * - k: the input shares (of course k <= n) 535*f0865ec9SKyle Evans * Output: 536*f0865ec9SKyle Evans * - shares: a pointer to the generated n shares (among which the k first are 537*f0865ec9SKyle Evans * the ones provided as inputs) 538*f0865ec9SKyle Evans * - secret: the recomputed secret value 539*f0865ec9SKyle Evans */ 540*f0865ec9SKyle Evans int sss_regenerate(sss_share *shares, unsigned short k, unsigned short n, sss_secret *secret) 541*f0865ec9SKyle Evans { 542*f0865ec9SKyle Evans int ret, cmp; 543*f0865ec9SKyle Evans unsigned int i; 544*f0865ec9SKyle Evans u16 max_idx, num_shares; 545*f0865ec9SKyle Evans u8 hmac_val[SSS_HMAC_SIZE]; 546*f0865ec9SKyle Evans u8 len; 547*f0865ec9SKyle Evans 548*f0865ec9SKyle Evans /* Sanity check */ 549*f0865ec9SKyle Evans MUST_HAVE((n <= (u16)(0xffff - 1)), ret, err); 550*f0865ec9SKyle Evans MUST_HAVE((n >= k), ret, err); 551*f0865ec9SKyle Evans 552*f0865ec9SKyle Evans ret = local_memset(hmac_val, 0, sizeof(hmac_val)); EG(ret, err); 553*f0865ec9SKyle Evans 554*f0865ec9SKyle Evans /* Compute the secret */ 555*f0865ec9SKyle Evans ret = _sss_raw_lagrange(shares, k, secret, 0); EG(ret, err); 556*f0865ec9SKyle Evans /* Check the authenticity of our shares */ 557*f0865ec9SKyle Evans for(i = 0; i < k; i++){ 558*f0865ec9SKyle Evans _sss_raw_share *cur_share = &(shares[i].raw_share); 559*f0865ec9SKyle Evans u8 *cur_id = (u8*)&(shares[i].session_id); 560*f0865ec9SKyle Evans u8 *cur_id0 = (u8*)&(shares[0].session_id); 561*f0865ec9SKyle Evans u8 *cur_share_hmac = (u8*)&(shares[i].raw_share_hmac); 562*f0865ec9SKyle Evans /* NOTE: we 'abuse' casts here for shares[i].raw_share to u8*, but this should be OK since 563*f0865ec9SKyle Evans * our structures are packed. 564*f0865ec9SKyle Evans */ 565*f0865ec9SKyle Evans const u8 *inputs[3] = { (const u8*)cur_share, cur_id, NULL }; 566*f0865ec9SKyle Evans const u32 ilens[3] = { sizeof(*cur_share), SSS_SESSION_ID_SIZE, 0 }; 567*f0865ec9SKyle Evans 568*f0865ec9SKyle Evans /* Check that all our shares have the same session ID, return an error otherwise */ 569*f0865ec9SKyle Evans ret = are_equal(cur_id, cur_id0, SSS_SESSION_ID_SIZE, &cmp); EG(ret, err); 570*f0865ec9SKyle Evans if(!cmp){ 571*f0865ec9SKyle Evans #ifdef VERBOSE 572*f0865ec9SKyle Evans ext_printf("[-] sss_regenerate error for share %d / %d: session ID is not OK!\n", i, k); 573*f0865ec9SKyle Evans #endif 574*f0865ec9SKyle Evans ret = -1; 575*f0865ec9SKyle Evans goto err; 576*f0865ec9SKyle Evans } 577*f0865ec9SKyle Evans 578*f0865ec9SKyle Evans len = sizeof(hmac_val); 579*f0865ec9SKyle Evans /* NOTE: we 'abuse' cast here for secret to (const u8*), but this should be OK since our 580*f0865ec9SKyle Evans * structures are packed. 581*f0865ec9SKyle Evans */ 582*f0865ec9SKyle Evans ret = hmac_scattered((const u8*)secret, SSS_SECRET_SIZE, SHA256, inputs, ilens, hmac_val, &len); EG(ret, err); 583*f0865ec9SKyle Evans ret = are_equal(hmac_val, cur_share_hmac, len, &cmp); EG(ret, err); 584*f0865ec9SKyle Evans if(!cmp){ 585*f0865ec9SKyle Evans #ifdef VERBOSE 586*f0865ec9SKyle Evans ext_printf("[-] sss_regenerate error for share %d / %d: HMAC is not OK!\n", i, k); 587*f0865ec9SKyle Evans #endif 588*f0865ec9SKyle Evans ret = -1; 589*f0865ec9SKyle Evans goto err; 590*f0865ec9SKyle Evans } 591*f0865ec9SKyle Evans } 592*f0865ec9SKyle Evans 593*f0865ec9SKyle Evans /* Our secret regeneration consists of determining the maximum index, and 594*f0865ec9SKyle Evans * proceed with Lagrange interpolation on new values. 595*f0865ec9SKyle Evans */ 596*f0865ec9SKyle Evans max_idx = 0; 597*f0865ec9SKyle Evans for(i = 0; i < k; i++){ 598*f0865ec9SKyle Evans u16 curr_idx; 599*f0865ec9SKyle Evans GET_UINT16_BE(curr_idx, (u8*)&(shares[i].raw_share.index), 0); 600*f0865ec9SKyle Evans if(curr_idx > max_idx){ 601*f0865ec9SKyle Evans max_idx = curr_idx; 602*f0865ec9SKyle Evans } 603*f0865ec9SKyle Evans } 604*f0865ec9SKyle Evans /* Now regenerate as many shares as we need */ 605*f0865ec9SKyle Evans num_shares = 0; 606*f0865ec9SKyle Evans i = k; 607*f0865ec9SKyle Evans while(num_shares < (n - k)){ 608*f0865ec9SKyle Evans _sss_raw_share *cur_share = &(shares[k + num_shares].raw_share); 609*f0865ec9SKyle Evans u8 *cur_id = (u8*)&(shares[k + num_shares].session_id); 610*f0865ec9SKyle Evans u8 *cur_id0 = (u8*)&(shares[0].session_id); 611*f0865ec9SKyle Evans u8 *cur_share_hmac = (u8*)&(shares[k + num_shares].raw_share_hmac); 612*f0865ec9SKyle Evans u16 curr_idx; 613*f0865ec9SKyle Evans /* NOTE: we 'abuse' casts here for shares[i].raw_share.share to sss_secret*, but this should be OK since 614*f0865ec9SKyle Evans * our shares[i].raw_share.share is a SSS_SECRET_SIZE as the sss_secret.secret type encapsulates and our 615*f0865ec9SKyle Evans * structures are packed. 616*f0865ec9SKyle Evans */ 617*f0865ec9SKyle Evans const u8 *inputs[3] = { (const u8*)cur_share, cur_id, NULL }; 618*f0865ec9SKyle Evans const u32 ilens[3] = { sizeof(*cur_share), SSS_SESSION_ID_SIZE, 0 }; 619*f0865ec9SKyle Evans 620*f0865ec9SKyle Evans /* Skip the index = 0 case */ 621*f0865ec9SKyle Evans curr_idx = (u16)(max_idx + (u16)(i - k + 1)); 622*f0865ec9SKyle Evans if(curr_idx == 0){ 623*f0865ec9SKyle Evans i++; 624*f0865ec9SKyle Evans continue; 625*f0865ec9SKyle Evans } 626*f0865ec9SKyle Evans 627*f0865ec9SKyle Evans /* Copy our session ID */ 628*f0865ec9SKyle Evans ret = local_memcpy(cur_id, cur_id0, SSS_SESSION_ID_SIZE); EG(ret, err); 629*f0865ec9SKyle Evans 630*f0865ec9SKyle Evans ret = _sss_raw_lagrange(shares, k, (sss_secret*)(cur_share->share), curr_idx); EG(ret, err); 631*f0865ec9SKyle Evans PUT_UINT16_BE(curr_idx, (u8*)&(cur_share->index), 0); 632*f0865ec9SKyle Evans 633*f0865ec9SKyle Evans /* Compute the HMAC */ 634*f0865ec9SKyle Evans len = SSS_HMAC_SIZE; 635*f0865ec9SKyle Evans ret = hmac_scattered((const u8*)secret, SSS_SECRET_SIZE, SHA256, inputs, ilens, cur_share_hmac, &len); EG(ret, err); 636*f0865ec9SKyle Evans num_shares++; 637*f0865ec9SKyle Evans i++; 638*f0865ec9SKyle Evans } 639*f0865ec9SKyle Evans 640*f0865ec9SKyle Evans err: 641*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(hmac_val, 0, sizeof(hmac_val))); 642*f0865ec9SKyle Evans 643*f0865ec9SKyle Evans return ret; 644*f0865ec9SKyle Evans } 645*f0865ec9SKyle Evans 646*f0865ec9SKyle Evans 647*f0865ec9SKyle Evans /********* main test program for SSS *************/ 648*f0865ec9SKyle Evans #ifdef SSS 649*f0865ec9SKyle Evans #include <libecc/utils/print_buf.h> 650*f0865ec9SKyle Evans 651*f0865ec9SKyle Evans #define K 50 652*f0865ec9SKyle Evans #define N 150 653*f0865ec9SKyle Evans #define MAX_N 200 654*f0865ec9SKyle Evans 655*f0865ec9SKyle Evans int main(int argc, char *argv[]) 656*f0865ec9SKyle Evans { 657*f0865ec9SKyle Evans int ret = 0; 658*f0865ec9SKyle Evans unsigned int i; 659*f0865ec9SKyle Evans sss_share shares[MAX_N]; 660*f0865ec9SKyle Evans sss_share shares_[MAX_N]; 661*f0865ec9SKyle Evans sss_secret secret; 662*f0865ec9SKyle Evans 663*f0865ec9SKyle Evans FORCE_USED_VAR(argc); 664*f0865ec9SKyle Evans FORCE_USED_VAR(argv); 665*f0865ec9SKyle Evans 666*f0865ec9SKyle Evans /* Generate N shares for SSS with at least K shares OK among N */ 667*f0865ec9SKyle Evans ext_printf("[+] Generating the secrets %d / %d, call should be OK\n", K, N); 668*f0865ec9SKyle Evans ret = local_memset(&secret, 0x00, sizeof(secret)); EG(ret, err); 669*f0865ec9SKyle Evans /* NOTE: 'false' here means that we let the library generate the secret randomly */ 670*f0865ec9SKyle Evans ret = sss_generate(shares, K, N, &secret, SSS_FALSE); 671*f0865ec9SKyle Evans if(ret){ 672*f0865ec9SKyle Evans ext_printf(" [X] Error: sss_generate error\n"); 673*f0865ec9SKyle Evans goto err; 674*f0865ec9SKyle Evans } 675*f0865ec9SKyle Evans else{ 676*f0865ec9SKyle Evans buf_print(" secret", (u8*)&secret, SSS_SECRET_SIZE); EG(ret, err); 677*f0865ec9SKyle Evans } 678*f0865ec9SKyle Evans /* Shuffle shares */ 679*f0865ec9SKyle Evans for(i = 0; i < N; i++){ 680*f0865ec9SKyle Evans shares_[i] = shares[N - 1 - i]; 681*f0865ec9SKyle Evans } 682*f0865ec9SKyle Evans 683*f0865ec9SKyle Evans /* Combine (k-1) shares: this call should trigger an ERROR */ 684*f0865ec9SKyle Evans ext_printf("[+] Combining the secrets with less shares: call should trigger an error\n"); 685*f0865ec9SKyle Evans ret = local_memset(&secret, 0x00, sizeof(secret)); EG(ret, err); 686*f0865ec9SKyle Evans ret = sss_combine(shares_, K - 1, &secret); 687*f0865ec9SKyle Evans if (ret) { 688*f0865ec9SKyle Evans ext_printf(" [X] Error: sss_combine error\n"); 689*f0865ec9SKyle Evans } else{ 690*f0865ec9SKyle Evans buf_print(" secret", (u8*)&secret, SSS_SECRET_SIZE); 691*f0865ec9SKyle Evans } 692*f0865ec9SKyle Evans 693*f0865ec9SKyle Evans /* Combine k shares: this call should be OK and recombine the initial 694*f0865ec9SKyle Evans * secret 695*f0865ec9SKyle Evans */ 696*f0865ec9SKyle Evans ext_printf("[+] Combining the secrets with minimum shares: call should be OK\n"); 697*f0865ec9SKyle Evans ret = local_memset(&secret, 0x00, sizeof(secret)); EG(ret, err); 698*f0865ec9SKyle Evans ret = sss_combine(shares_, K, &secret); 699*f0865ec9SKyle Evans if (ret) { 700*f0865ec9SKyle Evans ext_printf(" [X] Error: sss_combine error\n"); 701*f0865ec9SKyle Evans goto err; 702*f0865ec9SKyle Evans } else { 703*f0865ec9SKyle Evans buf_print(" secret", (u8*)&secret, SSS_SECRET_SIZE); 704*f0865ec9SKyle Evans } 705*f0865ec9SKyle Evans 706*f0865ec9SKyle Evans /* Combine k shares: this call should be OK and recombine the initial 707*f0865ec9SKyle Evans * secret 708*f0865ec9SKyle Evans */ 709*f0865ec9SKyle Evans ext_printf("[+] Combining the secrets with more shares: call should be OK\n"); 710*f0865ec9SKyle Evans ret = local_memset(&secret, 0x00, sizeof(secret)); EG(ret, err); 711*f0865ec9SKyle Evans ret = sss_combine(shares_, K + 1, &secret); 712*f0865ec9SKyle Evans if (ret) { 713*f0865ec9SKyle Evans ext_printf(" [X] Error: sss_combine error\n"); 714*f0865ec9SKyle Evans goto err; 715*f0865ec9SKyle Evans } else { 716*f0865ec9SKyle Evans buf_print(" secret", (u8*)&secret, SSS_SECRET_SIZE); 717*f0865ec9SKyle Evans } 718*f0865ec9SKyle Evans 719*f0865ec9SKyle Evans /* Combine with a corrupted share: call should trigger an error */ 720*f0865ec9SKyle Evans ext_printf("[+] Combining the secrets with more shares but one corrupted: call should trigger an error\n"); 721*f0865ec9SKyle Evans ret = local_memset(&secret, 0x00, sizeof(secret)); EG(ret, err); 722*f0865ec9SKyle Evans shares_[K].raw_share.share[0] = 0x00; 723*f0865ec9SKyle Evans ret = sss_combine(shares_, K + 1, &secret); 724*f0865ec9SKyle Evans if (ret) { 725*f0865ec9SKyle Evans ext_printf(" [X] Error: sss_combine error\n"); 726*f0865ec9SKyle Evans } else { 727*f0865ec9SKyle Evans buf_print(" secret", (u8*)&secret, SSS_SECRET_SIZE); 728*f0865ec9SKyle Evans } 729*f0865ec9SKyle Evans 730*f0865ec9SKyle Evans /* Regenerate more shares! call should be OK */ 731*f0865ec9SKyle Evans ext_printf("[+] Regenerating more shares: call should be OK\n"); 732*f0865ec9SKyle Evans ret = local_memset(&secret, 0x00, sizeof(secret)); EG(ret, err); 733*f0865ec9SKyle Evans ret = sss_regenerate(shares, K, MAX_N, &secret); EG(ret, err); 734*f0865ec9SKyle Evans if (ret) { 735*f0865ec9SKyle Evans ext_printf(" [X] Error: sss_regenerate error\n"); 736*f0865ec9SKyle Evans goto err; 737*f0865ec9SKyle Evans } else { 738*f0865ec9SKyle Evans buf_print(" secret", (u8*)&secret, SSS_SECRET_SIZE); 739*f0865ec9SKyle Evans } 740*f0865ec9SKyle Evans /* Shuffle shares */ 741*f0865ec9SKyle Evans for(i = 0; i < MAX_N; i++){ 742*f0865ec9SKyle Evans shares_[i] = shares[MAX_N - 1 - i]; 743*f0865ec9SKyle Evans } 744*f0865ec9SKyle Evans 745*f0865ec9SKyle Evans /* Combine newly generated shares: call should be OK */ 746*f0865ec9SKyle Evans ext_printf("[+] Combining the secrets with newly generated shares: call should be OK\n"); 747*f0865ec9SKyle Evans ret = local_memset(&secret, 0x00, sizeof(secret)); EG(ret, err); 748*f0865ec9SKyle Evans ret = sss_combine(shares_, K, &secret); 749*f0865ec9SKyle Evans if (ret) { 750*f0865ec9SKyle Evans ext_printf(" [X] Error: sss_combine error\n"); 751*f0865ec9SKyle Evans goto err; 752*f0865ec9SKyle Evans } else { 753*f0865ec9SKyle Evans buf_print(" secret", (u8*)&secret, SSS_SECRET_SIZE); 754*f0865ec9SKyle Evans } 755*f0865ec9SKyle Evans 756*f0865ec9SKyle Evans /* Modify the session ID of one of the shares: call should trigger an error */ 757*f0865ec9SKyle Evans ext_printf("[+] Combining the secrets with newly generated shares and a bad session ID: call should trigger an error\n"); 758*f0865ec9SKyle Evans ret = local_memset(&secret, 0x00, sizeof(secret)); EG(ret, err); 759*f0865ec9SKyle Evans shares_[1].session_id[0] = 0x00; 760*f0865ec9SKyle Evans ret = sss_combine(shares_, K, &secret); 761*f0865ec9SKyle Evans if (ret) { 762*f0865ec9SKyle Evans ext_printf(" [X] Error: sss_combine error\n"); 763*f0865ec9SKyle Evans } else { 764*f0865ec9SKyle Evans buf_print(" secret", (u8*)&secret, SSS_SECRET_SIZE); 765*f0865ec9SKyle Evans } 766*f0865ec9SKyle Evans 767*f0865ec9SKyle Evans ret = 0; 768*f0865ec9SKyle Evans 769*f0865ec9SKyle Evans err: 770*f0865ec9SKyle Evans return ret; 771*f0865ec9SKyle Evans } 772*f0865ec9SKyle Evans #endif 773