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