1 /*
2 * Copyright (C) 2021 - This file is part of libecc project
3 *
4 * Authors:
5 * Ryad BENADJILA <ryadbenadjila@gmail.com>
6 * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7 *
8 * This software is licensed under a dual BSD and GPL v2 license.
9 * See LICENSE file at the root folder of the project.
10 */
11 #include "sdsa.h"
12
13
14 /* We include the rand external dependency because we have to generate
15 * some random data for the nonces.
16 */
17 #include <libecc/external_deps/rand.h>
18 /* We include the printf external dependency for printf output */
19 #include <libecc/external_deps/print.h>
20 /* We include our common helpers */
21 #include "../common/common.h"
22
23 /*
24 * The purpose of this example is to implement the Schnorr signature
25 * scheme (aka SDSA for Schnorr DSA) based on libecc arithmetic primitives.
26 * Many "variants" of Schnorr signature schemes exist, we implement here the
27 * one corresponding to SDSA as described in the ISO14888-3 standard.
28 *
29 * XXX: Please be aware that libecc has been designed for Elliptic
30 * Curve cryptography, and as so the arithmetic primitives are
31 * not optimized for big numbers >= 1024 bits usually used for SDSA.
32 * Additionnaly, a hard limit of our NN values makes it impossible
33 * to exceed ~5300 bits in the best case (words of size 64 bits).
34 *
35 * All in all, please see this as a proof of concept.
36 * Use it at your own risk!
37 *
38 * !! DISCLAIMER !!
39 * ================
40 *
41 * Althoug some efforts have been made to secure this implementation
42 * of Schnorr DSA (e.g. by protecting the private key and nonces using constant
43 * time and blinding WHEN activated with BLINDING=1), please consider this
44 * code as a proof of concept and use it at your own risk.
45 *
46 * All-in-all, this piece of code can be useful in some contexts, or risky to
47 * use in other sensitive ones where advanced side-channels or fault attacks
48 * have to be considered. Use this SDSA code knowingly and at your own risk!
49 *
50 */
51
52 /* NOTE: since SDSA is very similar to DSA, we reuse some of our DSA
53 * primitives to factorize some code. Also, SDSA private and public keys
54 * have the exact same type as DSA keys.
55 */
56
57 /* Import a SDSA private key from buffers */
sdsa_import_priv_key(sdsa_priv_key * priv,const u8 * p,u16 plen,const u8 * q,u16 qlen,const u8 * g,u16 glen,const u8 * x,u16 xlen)58 int sdsa_import_priv_key(sdsa_priv_key *priv, const u8 *p, u16 plen,
59 const u8 *q, u16 qlen,
60 const u8 *g, u16 glen,
61 const u8 *x, u16 xlen)
62 {
63 return dsa_import_priv_key(priv, p, plen, q, qlen, g, glen, x, xlen);
64 }
65
66 /* Import a SDSA public key from buffers */
sdsa_import_pub_key(sdsa_pub_key * pub,const u8 * p,u16 plen,const u8 * q,u16 qlen,const u8 * g,u16 glen,const u8 * y,u16 ylen)67 int sdsa_import_pub_key(sdsa_pub_key *pub, const u8 *p, u16 plen,
68 const u8 *q, u16 qlen,
69 const u8 *g, u16 glen,
70 const u8 *y, u16 ylen)
71 {
72 return dsa_import_pub_key(pub, p, plen, q, qlen, g, glen, y, ylen);
73 }
74
75
76
77 /* Compute a SDSA public key from a private key.
78 * The public key is computed using modular exponentiation of the generator
79 * with the private key.
80 */
sdsa_compute_pub_from_priv(sdsa_pub_key * pub,const sdsa_priv_key * priv)81 int sdsa_compute_pub_from_priv(sdsa_pub_key *pub, const sdsa_priv_key *priv)
82 {
83 return dsa_compute_pub_from_priv(pub, priv);
84 }
85
86 /* Generate a SDSA signature
87 */
sdsa_sign(const sdsa_priv_key * priv,const u8 * msg,u32 msglen,const u8 * nonce,u16 noncelen,u8 * sig,u16 siglen,gen_hash_alg_type sdsa_hash)88 int sdsa_sign(const sdsa_priv_key *priv, const u8 *msg, u32 msglen,
89 const u8 *nonce, u16 noncelen,
90 u8 *sig, u16 siglen, gen_hash_alg_type sdsa_hash)
91 {
92 int ret, iszero;
93 /* alpha is the bit length of p, beta is the bit length of q */
94 bitcnt_t alpha, beta;
95 /* Length of the hash function (hlen is "gamma") */
96 u8 hlen, block_size;
97 nn_src_t p, q, g, x;
98 /* The nonce and its protected version */
99 nn k, k_;
100 /* r, s, pi */
101 nn r, s;
102 nn_t pi;
103 /* This is a bit too much for stack space, but we need it for
104 * the computation of "pi" I2BS representation ...
105 */
106 u8 pi_buf[NN_USABLE_MAX_BYTE_LEN];
107 /* hash context */
108 gen_hash_context hash_ctx;
109 #ifdef USE_SIG_BLINDING
110 /* b is the blinding mask */
111 nn b;
112 b.magic = WORD(0);
113 #endif /* USE_SIG_BLINDING */
114 k.magic = k_.magic = r.magic = s.magic = WORD(0);
115
116 /* Sanity checks */
117 MUST_HAVE((priv != NULL) && (msg != NULL) && (sig != NULL), ret, err);
118
119 ret = local_memset(pi_buf, 0, sizeof(pi_buf)); EG(ret, err);
120
121 /* Make things more readable */
122 p = &(priv->p);
123 q = &(priv->q);
124 g = &(priv->g);
125 x = &(priv->x);
126
127 /* Sanity checks */
128 ret = nn_check_initialized(p); EG(ret, err);
129 ret = nn_check_initialized(q); EG(ret, err);
130 ret = nn_check_initialized(g); EG(ret, err);
131 ret = nn_check_initialized(x); EG(ret, err);
132
133 /* Let alpha be the bit length of p */
134 ret = nn_bitlen(p, &alpha); EG(ret, err);
135 /* Let beta be the bit length of q */
136 ret = nn_bitlen(q, &beta); EG(ret, err);
137 /* Get the hash sizes (8*"gamma") */
138 ret = gen_hash_get_hash_sizes(sdsa_hash, &hlen, &block_size); EG(ret, err);
139 MUST_HAVE((hlen <= MAX_DIGEST_SIZE), ret, err);
140
141 /* Sanity check on the signature length:
142 * the signature is of size hash function plus an integer modulo q
143 * "gamma" + beta
144 */
145 MUST_HAVE((siglen == (hlen + BYTECEIL(beta))), ret, err);
146
147 restart:
148 /* If the nonce is imposed, use it. Else get a random modulo q */
149 if(nonce != NULL){
150 ret = _os2ip(&k, nonce, noncelen); EG(ret, err);
151 }
152 else{
153 ret = nn_get_random_mod(&k, q); EG(ret, err);
154 }
155
156 /* Fix the MSB of our scalar */
157 ret = nn_copy(&k_, &k); EG(ret, err);
158 #ifdef USE_SIG_BLINDING
159 /* Blind the scalar */
160 ret = _blind_scalar(&k_, q, &k_); EG(ret, err);
161 #endif /* USE_SIG_BLINDING */
162 ret = _fix_scalar_msb(&k_, q, &k_); EG(ret, err);
163 /* Use r as aliasing for pi to save some space */
164 pi = &r;
165 /* pi = (g**k mod p) */
166 ret = nn_init(pi, 0); EG(ret, err);
167 /* Exponentiation modulo p */
168 ret = nn_mod_pow(pi, g, &k_, p); EG(ret, err);
169
170 /* Compute I2BS(alpha, pi)
171 */
172 ret = _i2osp(pi, pi_buf, (u16)BYTECEIL(alpha)); EG(ret, err);
173
174 /* r = h(I2BS(alpha, pi) || M) */
175 ret = gen_hash_init(&hash_ctx, sdsa_hash); EG(ret, err);
176 ret = gen_hash_update(&hash_ctx, pi_buf, (u16)BYTECEIL(alpha), sdsa_hash); EG(ret, err);
177 ret = gen_hash_update(&hash_ctx, msg, msglen, sdsa_hash); EG(ret, err);
178 /* Export r result of the hash function in sig */
179 ret = gen_hash_final(&hash_ctx, sig, sdsa_hash); EG(ret, err);
180
181 /* Import r as an integer modulo q */
182 ret = _os2ip(&r, sig, hlen); EG(ret, err);
183 ret = nn_mod(&r, &r, q); EG(ret, err);
184
185 /* If r is 0, restart the process */
186 ret = nn_iszero(&r, &iszero); EG(ret, err);
187 if (iszero) {
188 IGNORE_RET_VAL(local_memset(sig, 0, hlen));
189 goto restart;
190 }
191
192 #ifdef USE_SIG_BLINDING
193 /* Note: if we use blinding, r and k are multiplied by
194 * a random value b in ]0,q[ */
195 ret = nn_get_random_mod(&b, q); EG(ret, err);
196 /* Blind r with b */
197 ret = nn_mod_mul(&r, &r, &b, q); EG(ret, err);
198 /* Blind k with b */
199 ret = nn_mod_mul(&k, &k, &b, q); EG(ret, err);
200 /*
201 * In case of blinding, we compute b^-1 with
202 * little Fermat theorem. This will be used to
203 * unblind s.
204 */
205 ret = nn_modinv_fermat(&b, &b, q); EG(ret, err);
206 #endif /* USE_SIG_BLINDING */
207
208 /* Compute s = (k + r x) mod q */
209 ret = nn_mod_mul(&s, &r, x, q); EG(ret, err);
210 ret = nn_mod_add(&s, &s, &k, q); EG(ret, err);
211
212 #ifdef USE_SIG_BLINDING
213 /* In case of blinding, unblind s */
214 ret = nn_mod_mul(&s, &s, &b, q); EG(ret, err);
215 #endif /* USE_SIG_BLINDING */
216 /* If s is 0, restart the process */
217 ret = nn_iszero(&s, &iszero); EG(ret, err);
218 if (iszero) {
219 goto restart;
220 }
221
222 /* Export s */
223 ret = _i2osp(&s, sig + hlen, (u16)(siglen - hlen)); EG(ret, err);
224
225 err:
226 if(ret && (sig != NULL)){
227 IGNORE_RET_VAL(local_memset(sig, 0, siglen));
228 }
229
230 nn_uninit(&k);
231 nn_uninit(&k_);
232 #ifdef USE_SIG_BLINDING
233 nn_uninit(&b);
234 #endif
235 nn_uninit(&r);
236 nn_uninit(&s);
237
238 PTR_NULLIFY(pi);
239
240 PTR_NULLIFY(p);
241 PTR_NULLIFY(q);
242 PTR_NULLIFY(g);
243 PTR_NULLIFY(x);
244
245 return ret;
246 }
247
248
249
250 /* Verify a SDSA signature
251 */
sdsa_verify(const sdsa_pub_key * pub,const u8 * msg,u32 msglen,const u8 * sig,u16 siglen,gen_hash_alg_type sdsa_hash)252 int sdsa_verify(const sdsa_pub_key *pub, const u8 *msg, u32 msglen,
253 const u8 *sig, u16 siglen, gen_hash_alg_type sdsa_hash)
254 {
255 int ret, iszero, cmp;
256 /* alpha is the bit length of p, beta is the bit length of q */
257 bitcnt_t alpha, beta;
258 /* Length of the hash function */
259 u8 hlen, block_size;
260 nn_src_t p, q, g, y;
261 /* r, s */
262 nn r, s;
263 /* u, and pi */
264 nn u, pi;
265 /* This is a bit too much for stack space, but we need it for
266 * the computation of "pi" I2BS representation ...
267 */
268 u8 pi_buf[NN_USABLE_MAX_BYTE_LEN];
269 /* Hash */
270 u8 hash[MAX_DIGEST_SIZE];
271 /* hash context */
272 gen_hash_context hash_ctx;
273 r.magic = s.magic = u.magic = pi.magic = WORD(0);
274
275 /* Sanity checks */
276 MUST_HAVE((pub != NULL) && (msg != NULL) && (sig != NULL), ret, err);
277
278 ret = local_memset(pi_buf, 0, sizeof(pi_buf)); EG(ret, err);
279 ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
280
281 /* Make things more readable */
282 p = &(pub->p);
283 q = &(pub->q);
284 g = &(pub->g);
285 y = &(pub->y);
286
287 /* Sanity checks */
288 ret = nn_check_initialized(p); EG(ret, err);
289 ret = nn_check_initialized(q); EG(ret, err);
290 ret = nn_check_initialized(g); EG(ret, err);
291 ret = nn_check_initialized(y); EG(ret, err);
292
293 /* Let alpha be the bit length of p */
294 ret = nn_bitlen(p, &alpha); EG(ret, err);
295 /* Let beta be the bit length of q */
296 ret = nn_bitlen(q, &beta); EG(ret, err);
297 /* Get the hash sizes (8*"gamma") */
298 ret = gen_hash_get_hash_sizes(sdsa_hash, &hlen, &block_size); EG(ret, err);
299 MUST_HAVE((hlen <= MAX_DIGEST_SIZE), ret, err);
300
301 /* Sanity check on the signature length */
302 MUST_HAVE((siglen == (hlen + BYTECEIL(beta))), ret, err);
303
304 /* Extract r and s */
305 ret = _os2ip(&r, sig, hlen); EG(ret, err);
306 ret = _os2ip(&s, sig + hlen, (u16)(siglen - hlen)); EG(ret, err);
307
308 /* Return an error if r = 0 or s = 0 */
309 ret = nn_iszero(&r, &iszero); EG(ret, err);
310 MUST_HAVE((!iszero), ret, err);
311 ret = nn_iszero(&s, &iszero); EG(ret, err);
312 MUST_HAVE((!iszero), ret, err);
313 /* Check that 0 < s < q */
314 ret = nn_cmp(&s, q, &cmp); EG(ret, err);
315 MUST_HAVE((cmp < 0), ret, err);
316
317 /* Take r modulo q */
318 ret = nn_mod(&r, &r, q); EG(ret, err);
319
320 /* Initialize internal variables */
321 ret = nn_init(&u, 0); EG(ret, err);
322 ret = nn_init(&pi, 0); EG(ret, err);
323
324 /* NOTE: no need to use a secure exponentiation here as we only
325 * manipulate public data.
326 */
327 /* Compute (y ** -r) mod (p) */
328 ret = nn_sub(&r, q, &r); EG(ret, err); /* compute -r = (q - r) mod q */
329 ret = _nn_mod_pow_insecure(&u, y, &r, p); EG(ret, err);
330 /* Compute (g ** s) mod (p) */
331 ret = _nn_mod_pow_insecure(&pi, g, &s, p); EG(ret, err);
332 /* Compute (y ** -r) * (g ** s) mod (p) */
333 ret = nn_mod_mul(&pi, &pi, &u, p); EG(ret, err);
334
335 /* Compute r' */
336 /* I2BS(alpha, pi)
337 */
338 ret = _i2osp(&pi, pi_buf, (u16)BYTECEIL(alpha)); EG(ret, err);
339 /* r' = h(I2BS(alpha, pi) || M) */
340 ret = gen_hash_init(&hash_ctx, sdsa_hash); EG(ret, err);
341 ret = gen_hash_update(&hash_ctx, pi_buf, (u16)BYTECEIL(alpha), sdsa_hash); EG(ret, err);
342 ret = gen_hash_update(&hash_ctx, msg, msglen, sdsa_hash); EG(ret, err);
343 ret = gen_hash_final(&hash_ctx, hash, sdsa_hash); EG(ret, err);
344
345 /* Check that hash values r' == r */
346 ret = are_equal(sig, hash, hlen, &cmp); EG(ret, err);
347 ret = (cmp != 1) ? -1 : 0;
348
349 err:
350 nn_uninit(&r);
351 nn_uninit(&s);
352 nn_uninit(&u);
353 nn_uninit(&pi);
354
355 PTR_NULLIFY(p);
356 PTR_NULLIFY(q);
357 PTR_NULLIFY(g);
358 PTR_NULLIFY(y);
359
360 return ret;
361 }
362
363 #ifdef SDSA
364 #include <libecc/utils/print_buf.h>
main(int argc,char * argv[])365 int main(int argc, char *argv[])
366 {
367 int ret = 0;
368
369 /* This example is taken from ISO14888-3 SDSA (Appendix F "Numerical examples" */
370 const u8 p[] = {
371 0x87, 0xA8, 0xE6, 0x1D, 0xB4, 0xB6, 0x66, 0x3C, 0xFF, 0xBB, 0xD1, 0x9C, 0x65, 0x19, 0x59, 0x99, 0x8C, 0xEE, 0xF6, 0x08, 0x66, 0x0D, 0xD0, 0xF2,
372 0x5D, 0x2C, 0xEE, 0xD4, 0x43, 0x5E, 0x3B, 0x00, 0xE0, 0x0D, 0xF8, 0xF1, 0xD6, 0x19, 0x57, 0xD4, 0xFA, 0xF7, 0xDF, 0x45, 0x61, 0xB2, 0xAA, 0x30,
373 0x16, 0xC3, 0xD9, 0x11, 0x34, 0x09, 0x6F, 0xAA, 0x3B, 0xF4, 0x29, 0x6D, 0x83, 0x0E, 0x9A, 0x7C, 0x20, 0x9E, 0x0C, 0x64, 0x97, 0x51, 0x7A, 0xBD,
374 0x5A, 0x8A, 0x9D, 0x30, 0x6B, 0xCF, 0x67, 0xED, 0x91, 0xF9, 0xE6, 0x72, 0x5B, 0x47, 0x58, 0xC0, 0x22, 0xE0, 0xB1, 0xEF, 0x42, 0x75, 0xBF, 0x7B,
375 0x6C, 0x5B, 0xFC, 0x11, 0xD4, 0x5F, 0x90, 0x88, 0xB9, 0x41, 0xF5, 0x4E, 0xB1, 0xE5, 0x9B, 0xB8, 0xBC, 0x39, 0xA0, 0xBF, 0x12, 0x30, 0x7F, 0x5C,
376 0x4F, 0xDB, 0x70, 0xC5, 0x81, 0xB2, 0x3F, 0x76, 0xB6, 0x3A, 0xCA, 0xE1, 0xCA, 0xA6, 0xB7, 0x90, 0x2D, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8A, 0x0E,
377 0xF1, 0x3C, 0x6D, 0x9A, 0x51, 0xBF, 0xA4, 0xAB, 0x3A, 0xD8, 0x34, 0x77, 0x96, 0x52, 0x4D, 0x8E, 0xF6, 0xA1, 0x67, 0xB5, 0xA4, 0x18, 0x25, 0xD9,
378 0x67, 0xE1, 0x44, 0xE5, 0x14, 0x05, 0x64, 0x25, 0x1C, 0xCA, 0xCB, 0x83, 0xE6, 0xB4, 0x86, 0xF6, 0xB3, 0xCA, 0x3F, 0x79, 0x71, 0x50, 0x60, 0x26,
379 0xC0, 0xB8, 0x57, 0xF6, 0x89, 0x96, 0x28, 0x56, 0xDE, 0xD4, 0x01, 0x0A, 0xBD, 0x0B, 0xE6, 0x21, 0xC3, 0xA3, 0x96, 0x0A, 0x54, 0xE7, 0x10, 0xC3,
380 0x75, 0xF2, 0x63, 0x75, 0xD7, 0x01, 0x41, 0x03, 0xA4, 0xB5, 0x43, 0x30, 0xC1, 0x98, 0xAF, 0x12, 0x61, 0x16, 0xD2, 0x27, 0x6E, 0x11, 0x71, 0x5F,
381 0x69, 0x38, 0x77, 0xFA, 0xD7, 0xEF, 0x09, 0xCA, 0xDB, 0x09, 0x4A, 0xE9, 0x1E, 0x1A, 0x15, 0x97,
382 };
383
384 const u8 q[] = {
385 0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97, 0xB4, 0x47, 0x99, 0x76, 0x40, 0x12, 0x9D, 0xA2, 0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B,
386 0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3,
387 };
388
389 const u8 g[] = {
390 0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B, 0x2E, 0x77, 0x50, 0x66, 0x60, 0xED, 0xBD, 0x48, 0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54,
391 0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25, 0x10, 0xDB, 0xC1, 0x50, 0x77, 0xBE, 0x46, 0x3F, 0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55,
392 0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1, 0xBC, 0x37, 0x73, 0xBF, 0x7E, 0x8C, 0x6F, 0x62, 0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18,
393 0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65, 0x01, 0x96, 0xF9, 0x31, 0xC7, 0x7A, 0x57, 0xF2, 0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B,
394 0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62, 0x8A, 0xC3, 0x76, 0xD2, 0x82, 0xD6, 0xED, 0x38, 0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83,
395 0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93, 0xB5, 0x04, 0x5A, 0xF2, 0x76, 0x71, 0x64, 0xE1, 0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55,
396 0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80, 0xD0, 0x52, 0xB9, 0x85, 0xD1, 0x82, 0xEA, 0x0A, 0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14,
397 0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9, 0xB7, 0xD2, 0xBB, 0xD2, 0xDF, 0x01, 0x61, 0x99, 0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15,
398 0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37, 0x7F, 0xD0, 0x28, 0x37, 0x0D, 0xF9, 0x2B, 0x52, 0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6,
399 0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3, 0x2F, 0x63, 0x07, 0x84, 0x90, 0xF0, 0x0E, 0xF8, 0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51,
400 0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82, 0x66, 0x4B, 0x4C, 0x0F, 0x6C, 0xC4, 0x16, 0x59,
401 };
402
403 const u8 x[] = {
404 0x73, 0x01, 0x88, 0x95, 0x20, 0xD4, 0x7A, 0xA0, 0x55, 0x99, 0x5B, 0xA1, 0xD8, 0xFC, 0xD7, 0x01, 0x6E, 0xA6, 0x2E, 0x09, 0x18, 0x89, 0x2E, 0x07,
405 0xB7, 0xDC, 0x23, 0xAF, 0x69, 0x00, 0x6B, 0x88,
406 };
407
408 const u8 y[] = {
409 0x57, 0xA1, 0x72, 0x58, 0xD4, 0xA3, 0xF4, 0x7C, 0x45, 0x45, 0xAD, 0x51, 0xF3, 0x10, 0x9C, 0x5D, 0xB4, 0x1B, 0x78, 0x78, 0x79, 0xFC, 0xFE, 0x53,
410 0x8D, 0xC1, 0xDD, 0x5D, 0x35, 0xCE, 0x42, 0xFF, 0x3A, 0x9F, 0x22, 0x5E, 0xDE, 0x65, 0x02, 0x12, 0x64, 0x08, 0xFC, 0xB1, 0x3A, 0xEA, 0x22, 0x31,
411 0x80, 0xB1, 0x49, 0xC4, 0x64, 0xE1, 0x76, 0xEB, 0xF0, 0x3B, 0xA6, 0x51, 0x0D, 0x82, 0x06, 0xC9, 0x20, 0xF6, 0xB1, 0xE0, 0x93, 0x92, 0xE6, 0xC8,
412 0x40, 0xA0, 0x5B, 0xDB, 0x9D, 0x68, 0x75, 0xAB, 0x3F, 0x48, 0x17, 0xEC, 0x3A, 0x65, 0xA6, 0x65, 0xB7, 0x88, 0xEC, 0xBB, 0x44, 0x71, 0x88, 0xC7,
413 0xDF, 0x2E, 0xB4, 0xD3, 0xD9, 0x42, 0x4E, 0x57, 0xD9, 0x64, 0x39, 0x8D, 0xBE, 0x1C, 0x63, 0x62, 0x65, 0x9C, 0x6B, 0xD8, 0x55, 0xC1, 0xD3, 0xE5,
414 0x1D, 0x64, 0x79, 0x6C, 0xA5, 0x98, 0x48, 0x0D, 0xFD, 0xD9, 0x58, 0x0E, 0x55, 0x08, 0x53, 0x45, 0xC1, 0x5E, 0x34, 0xD6, 0xA3, 0x3A, 0x2F, 0x43,
415 0xE2, 0x22, 0x40, 0x7A, 0xCE, 0x05, 0x89, 0x72, 0xD3, 0x49, 0x52, 0xAE, 0x2B, 0x70, 0x5C, 0x53, 0x22, 0x43, 0xBE, 0x39, 0x4B, 0x22, 0x23, 0x29,
416 0x61, 0x61, 0x14, 0x5E, 0xF2, 0x92, 0x7C, 0xDB, 0xC5, 0x5B, 0xBD, 0x56, 0x4A, 0xAE, 0x8D, 0xE4, 0xBA, 0x45, 0x00, 0xA7, 0xFA, 0x43, 0x2F, 0xE7,
417 0x8B, 0x0F, 0x06, 0x89, 0x1E, 0x40, 0x80, 0x83, 0x7E, 0x76, 0x10, 0x57, 0xBC, 0x6C, 0xB8, 0xAC, 0x18, 0xFD, 0x43, 0x20, 0x75, 0x82, 0x03, 0x2A,
418 0xFB, 0x63, 0xC6, 0x24, 0xF3, 0x2E, 0x66, 0xB0, 0x5F, 0xC3, 0x1C, 0x5D, 0xFF, 0xB2, 0x5F, 0xA9, 0x2D, 0x4D, 0x00, 0xE2, 0xB0, 0xD4, 0xF7, 0x21,
419 0xE8, 0x8C, 0x41, 0x7D, 0x2E, 0x57, 0x79, 0x7B, 0x8F, 0x55, 0xA2, 0xFF, 0xC6, 0xEE, 0x4D, 0xDB,
420 };
421
422 const u8 msg[] = "abc";
423
424 const u8 nonce[] = {
425 0x2B, 0x73, 0xE8, 0xFF, 0x3A, 0x7C, 0x01, 0x68, 0x6C, 0xA5, 0x56, 0xE0, 0xFA, 0xBF, 0xD7, 0x4A, 0xC8, 0xD1, 0xFD, 0xA4, 0xAD, 0x3D, 0x50, 0x3F,
426 0x23, 0xB8, 0xEB, 0x8A, 0xEE, 0xC6, 0x33, 0x05,
427 };
428
429 sdsa_priv_key priv;
430 sdsa_pub_key pub;
431 sdsa_pub_key pub2;
432 u8 sig[32*2] = { 0 };
433
434 FORCE_USED_VAR(argc);
435 FORCE_USED_VAR(argv);
436
437 /* Sanity check on size for DSA.
438 * NOTE: the double parentheses are here to handle -Wunreachable-code
439 */
440 if((NN_USABLE_MAX_BIT_LEN) < (4096)){
441 ext_printf("Error: you seem to have compiled libecc with usable NN size < 4096, not suitable for DSA.\n");
442 ext_printf(" => Please recompile libecc with EXTRA_CFLAGS=\"-DUSER_NN_BIT_LEN=4096\"\n");
443 ext_printf(" This will increase usable NN for proper DSA up to 4096 bits.\n");
444 ext_printf(" Then recompile the current examples with the same EXTRA_CFLAGS=\"-DUSER_NN_BIT_LEN=4096\" flag and execute again!\n");
445 /* NOTE: ret = 0 here to pass self tests even if the library is not compatible */
446 ret = 0;
447 goto err;
448 }
449
450
451 ret = sdsa_import_priv_key(&priv, p, sizeof(p), q, sizeof(q), g, sizeof(g), x, sizeof(x)); EG(ret, err);
452 ret = sdsa_import_pub_key(&pub, p, sizeof(p), q, sizeof(q), g, sizeof(g), y, sizeof(y)); EG(ret, err);
453 ret = sdsa_compute_pub_from_priv(&pub2, &priv); EG(ret, err);
454
455 nn_print("y", &(pub2.y));
456
457 ret = sdsa_sign(&priv, msg, sizeof(msg)-1, nonce, sizeof(nonce), sig, sizeof(sig), HASH_SHA256); EG(ret, err);
458
459 buf_print("sig", sig, sizeof(sig));
460
461 ret = sdsa_verify(&pub, msg, sizeof(msg)-1, sig, sizeof(sig), HASH_SHA256);
462 ext_printf("Signature result %d\n", ret);
463
464 err:
465 return ret;
466 }
467 #endif
468