xref: /freebsd-src/crypto/libecc/src/examples/sss/sss.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
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