xref: /freebsd/crypto/libecc/src/examples/sig/gostr34_10_94/gostr34_10_94.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 "gostr34_10_94.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 GOSTR34-10-94
25  * based on libecc arithmetic primitives.
26  *
27  * XXX: Please be aware that libecc has been designed for Elliptic
28  * Curve cryptography, and as so the arithmetic primitives are
29  * not optimized for big numbers >= 1024 bits usually used for GOSTR.
30  * Additionnaly, a hard limit of our NN values makes it impossible
31  * to exceed ~5300 bits in the best case (words of size 64 bits).
32  *
33  * All in all, please see this as a proof of concept.
34  * Use it at your own risk!
35  *
36  * !! DISCLAIMER !!
37  * ================
38  *
39  * Althoug some efforts have been made to secure this implementation
40  * of GOSTR (e.g. by protecting the private key and nonces using constant
41  * time and blinding WHEN activated with BLINDING=1), please consider this
42  * code as a proof of concept and use it at your own risk.
43  *
44  * All-in-all, this piece of code can be useful in some contexts, or risky to
45  * use in other sensitive ones where advanced side-channels or fault attacks
46  * have to be considered. Use this GOSTR code knowingly and at your own risk!
47  *
48  */
49 
50 /* NOTE: since GOSTR34_10_94 is very similar to DSA, we reuse some of our DSA
51  * primitives to factorize some code. Also, GOSTR34_10_94 private and public keys
52  * have the exact same type as DSA keys.
53  */
54 
55 /* Import a GOSTR34_10_94 private key from buffers */
gostr34_10_94_import_priv_key(gostr34_10_94_priv_key * priv,const u8 * p,u16 plen,const u8 * q,u16 qlen,const u8 * g,u16 glen,const u8 * x,u16 xlen)56 int gostr34_10_94_import_priv_key(gostr34_10_94_priv_key *priv, const u8 *p, u16 plen,
57 			const u8 *q, u16 qlen,
58 			const u8 *g, u16 glen,
59 			const u8 *x, u16 xlen)
60 {
61 	return dsa_import_priv_key(priv, p, plen, q, qlen, g, glen, x, xlen);
62 }
63 
64 /* Import a GOSTR34_10_94 public key from buffers */
gostr34_10_94_import_pub_key(gostr34_10_94_pub_key * pub,const u8 * p,u16 plen,const u8 * q,u16 qlen,const u8 * g,u16 glen,const u8 * y,u16 ylen)65 int gostr34_10_94_import_pub_key(gostr34_10_94_pub_key *pub, const u8 *p, u16 plen,
66 			const u8 *q, u16 qlen,
67 			const u8 *g, u16 glen,
68 			const u8 *y, u16 ylen)
69 {
70 	return dsa_import_pub_key(pub, p, plen, q, qlen, g, glen, y, ylen);
71 }
72 
73 
74 
75 /* Compute a GOSTR34_10_94 public key from a private key.
76  * The public key is computed using modular exponentiation of the generator
77  * with the private key.
78  */
gostr34_10_94_compute_pub_from_priv(gostr34_10_94_pub_key * pub,const gostr34_10_94_priv_key * priv)79 int gostr34_10_94_compute_pub_from_priv(gostr34_10_94_pub_key *pub, const gostr34_10_94_priv_key *priv)
80 {
81 	return dsa_compute_pub_from_priv(pub, priv);
82 }
83 
84 /* Generate a GOSTR34_10_94 signature
85  */
gostr34_10_94_sign(const gostr34_10_94_priv_key * priv,const u8 * msg,u32 msglen,const u8 * nonce,u16 noncelen,u8 * sig,u16 siglen,gen_hash_alg_type gostr34_10_94_hash)86 int gostr34_10_94_sign(const gostr34_10_94_priv_key *priv, const u8 *msg, u32 msglen,
87 	     const u8 *nonce, u16 noncelen,
88 	     u8 *sig, u16 siglen, gen_hash_alg_type gostr34_10_94_hash)
89 {
90 	int ret, iszero;
91 	/* N is the bit length of q */
92 	bitcnt_t N, rshift;
93 	/* Length of the hash function */
94 	u8 hlen, block_size;
95 	nn_src_t p, q, g, x;
96 	/* The nonce and its protected version */
97 	nn k, k_;
98 	/* r, s and z */
99 	nn r, s, z;
100 	/* Hash */
101 	u8 hash[MAX_DIGEST_SIZE];
102 #ifdef USE_SIG_BLINDING
103 	/* b is the blinding mask */
104 	nn b;
105 	b.magic = WORD(0);
106 #endif /* USE_SIG_BLINDING */
107 	k.magic = k_.magic = r.magic = s.magic = z.magic = WORD(0);
108 
109 	/* Sanity checks */
110 	MUST_HAVE((priv != NULL) && (msg != NULL) && (sig != NULL), ret, err);
111 
112 	ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
113 
114 	/* Make things more readable */
115 	p = &(priv->p);
116 	q = &(priv->q);
117 	g = &(priv->g);
118 	x = &(priv->x);
119 
120 	/* Sanity checks */
121 	ret = nn_check_initialized(p); EG(ret, err);
122 	ret = nn_check_initialized(q); EG(ret, err);
123 	ret = nn_check_initialized(g); EG(ret, err);
124 	ret = nn_check_initialized(x); EG(ret, err);
125 
126 	/* Let N be the bit length of q. Let min(N, outlen) denote the minimum
127 	 * of the positive integers N and outlen, where outlen is the bit length
128 	 * of the hash function output block.
129 	 */
130 	ret = nn_bitlen(q, &N); EG(ret, err);
131 	ret = gen_hash_get_hash_sizes(gostr34_10_94_hash, &hlen, &block_size); EG(ret, err);
132 	MUST_HAVE((hlen <= MAX_DIGEST_SIZE), ret, err);
133 
134 	/* Sanity check on the signature length */
135 	MUST_HAVE((siglen == (2 * BYTECEIL(N))), ret, err);
136 
137 restart:
138 	/* If the nonce is imposed, use it. Else get a random modulo q */
139 	if(nonce != NULL){
140 		ret = _os2ip(&k, nonce, noncelen); EG(ret, err);
141 	}
142 	else{
143 		ret = nn_get_random_mod(&k, q); EG(ret, err);
144 	}
145 
146 	/* Fix the MSB of our scalar */
147 	ret = nn_copy(&k_, &k); EG(ret, err);
148 #ifdef USE_SIG_BLINDING
149 	/* Blind the scalar */
150 	ret = _blind_scalar(&k_, q, &k_); EG(ret, err);
151 #endif /* USE_SIG_BLINDING */
152 	ret = _fix_scalar_msb(&k_, q, &k_); EG(ret, err);
153 	/* r = (g**k mod p) mod q */
154 	ret = nn_init(&r, 0); EG(ret, err);
155 	/* Exponentiation modulo p */
156 	ret = nn_mod_pow(&r, g, &k_, p); EG(ret, err);
157 	/* Modulo q */
158 	ret = nn_mod(&r, &r, q); EG(ret, err);
159 
160 	/* If r is 0, restart the process */
161 	ret = nn_iszero(&r, &iszero); EG(ret, err);
162 	if (iszero) {
163 		goto restart;
164  	}
165 
166 	/* Export r */
167 	ret = _i2osp(&r, sig, (siglen / 2)); EG(ret, err);
168 
169 	/* Compute the hash */
170 	ret = gen_hash_hfunc(msg, msglen, hash, gostr34_10_94_hash); EG(ret, err);
171 	/* Reverse the endianness of the hash as little endian is needed here */
172 	ret = _reverse_endianness(hash, hlen); EG(ret, err);
173 
174 	/* z = the leftmost min(N, outlen) bits of Hash(M) */
175         rshift = 0;
176         if ((hlen * 8) > N) {
177                 rshift = (bitcnt_t)((hlen * 8) - N);
178         }
179 	ret = _os2ip(&z, hash, hlen); EG(ret, err);
180 	if (rshift) {
181 		ret = nn_rshift_fixedlen(&z, &z, rshift); EG(ret, err);
182 	}
183 	ret = nn_mod(&z, &z, q); EG(ret, err);
184 	/* If z = 0, then set it to 1 */
185 	ret = nn_iszero(&z, &iszero); EG(ret, err);
186 	if(iszero){
187 		ret = nn_one(&z); EG(ret, err);
188 	}
189 
190 #ifdef USE_SIG_BLINDING
191 	/* Note: if we use blinding, r and e are multiplied by
192 	 * a random value b in ]0,q[ */
193 	ret = nn_get_random_mod(&b, q); EG(ret, err);
194         /* Blind r with b */
195         ret = nn_mod_mul(&r, &r, &b, q); EG(ret, err);
196         /* Blind the message z */
197         ret = nn_mod_mul(&z, &z, &b, q); EG(ret, err);
198         /*
199          * In case of blinding, we compute b^-1 with
200 	 * little Fermat theorem. This will be used to
201 	 * unblind s.
202          */
203         ret = nn_modinv_fermat(&b, &b, q); EG(ret, err);
204 #endif /* USE_SIG_BLINDING */
205 
206 	/* Compute s = (xr + kz) mod q  */
207 	ret = nn_mod_mul(&s, &r, x, q); EG(ret, err);
208 	ret = nn_mod_mul(&r, &k, &z, q); EG(ret, err);
209 	ret = nn_mod_add(&s, &s, &r, q); EG(ret, err);
210 
211 #ifdef USE_SIG_BLINDING
212 	/* In case of blinding, unblind s */
213 	ret = nn_mod_mul(&s, &s, &b, q); EG(ret, err);
214 #endif /* USE_SIG_BLINDING */
215 	/* If s is 0, restart the process */
216 	ret = nn_iszero(&s, &iszero); EG(ret, err);
217 	if (iszero) {
218 		goto restart;
219  	}
220 
221 	/* Export s */
222 	ret = _i2osp(&s, sig + (siglen / 2), (siglen / 2));
223 
224 err:
225 	if(ret && (sig != NULL)){
226 		IGNORE_RET_VAL(local_memset(sig, 0, siglen));
227 	}
228 
229 	nn_uninit(&k);
230 	nn_uninit(&k_);
231 #ifdef USE_SIG_BLINDING
232 	nn_uninit(&b);
233 #endif
234 	nn_uninit(&r);
235 	nn_uninit(&s);
236 	nn_uninit(&z);
237 
238 	PTR_NULLIFY(p);
239 	PTR_NULLIFY(q);
240 	PTR_NULLIFY(g);
241 	PTR_NULLIFY(x);
242 
243 	return ret;
244 }
245 
246 
247 
248 /* Verify a GOSTR34_10_94 signature
249  */
gostr34_10_94_verify(const gostr34_10_94_pub_key * pub,const u8 * msg,u32 msglen,const u8 * sig,u16 siglen,gen_hash_alg_type gostr34_10_94_hash)250 int gostr34_10_94_verify(const gostr34_10_94_pub_key *pub, const u8 *msg, u32 msglen,
251 	     const u8 *sig, u16 siglen, gen_hash_alg_type gostr34_10_94_hash)
252 {
253 	int ret, iszero, cmp;
254 	/* N is the bit length of q */
255 	bitcnt_t N, rshift;
256 	/* Length of the hash function */
257 	u8 hlen, block_size;
258 	nn_src_t p, q, g, y;
259 	/* r, s */
260 	nn r, s, z;
261 	/* u1, u2, and v */
262 	nn u1, u2, v;
263 	/* Hash */
264 	u8 hash[MAX_DIGEST_SIZE];
265 	r.magic = s.magic = z.magic = u1.magic = u2.magic = WORD(0);
266 
267 	/* Sanity checks */
268 	MUST_HAVE((pub != NULL) && (msg != NULL) && (sig != NULL), ret, err);
269 
270 	ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
271 
272 	/* Make things more readable */
273 	p = &(pub->p);
274 	q = &(pub->q);
275 	g = &(pub->g);
276 	y = &(pub->y);
277 
278 	/* Sanity checks */
279 	ret = nn_check_initialized(p); EG(ret, err);
280 	ret = nn_check_initialized(q); EG(ret, err);
281 	ret = nn_check_initialized(g); EG(ret, err);
282 	ret = nn_check_initialized(y); EG(ret, err);
283 
284 	/* Sanity check on the signature length */
285 	ret = nn_bitlen(q, &N); EG(ret, err);
286 	MUST_HAVE((siglen == (2 * BYTECEIL(N))), ret, err);
287 
288 	/* Extract r and s */
289 	ret = _os2ip(&r, sig, (siglen / 2)); EG(ret, err);
290 	ret = _os2ip(&s, sig + (siglen / 2), (siglen / 2)); EG(ret, err);
291 
292 	/* Return an error if r = 0 or s = 0 */
293 	ret = nn_iszero(&r, &iszero); EG(ret, err);
294 	MUST_HAVE((!iszero), ret, err);
295 	ret = nn_iszero(&s, &iszero); EG(ret, err);
296 	MUST_HAVE((!iszero), ret, err);
297 	/* Check that 0 < r < q and 0 < s < q */
298 	ret = nn_cmp(&r, q, &cmp); EG(ret, err);
299 	MUST_HAVE((cmp < 0), ret, err);
300 	ret = nn_cmp(&s, q, &cmp); EG(ret, err);
301 	MUST_HAVE((cmp < 0), ret, err);
302 
303 	/* Compute the hash */
304 	ret = gen_hash_get_hash_sizes(gostr34_10_94_hash, &hlen, &block_size); EG(ret, err);
305 	MUST_HAVE((hlen <= MAX_DIGEST_SIZE), ret, err);
306 	ret = gen_hash_hfunc(msg, msglen, hash, gostr34_10_94_hash); EG(ret, err);
307 	/* Reverse the endianness of the hash as little endian is needed here */
308 	ret = _reverse_endianness(hash, hlen); EG(ret, err);
309 
310 	/* z = the leftmost min(N, outlen) bits of Hash(M) */
311         rshift = 0;
312         if ((hlen * 8) > N) {
313                 rshift = (bitcnt_t)((hlen * 8) - N);
314         }
315 	ret = _os2ip(&z, hash, hlen); EG(ret, err);
316 	if (rshift) {
317 		ret = nn_rshift_fixedlen(&z, &z, rshift); EG(ret, err);
318 	}
319 	ret = nn_mod(&z, &z, q); EG(ret, err);
320 	/* If z = 0, then set it to 1 */
321 	ret = nn_iszero(&z, &iszero); EG(ret, err);
322 	if(iszero){
323 		ret = nn_one(&z); EG(ret, err);
324 	}
325 
326 	/* Initialize internal variables */
327 	ret = nn_init(&v, 0); EG(ret, err);
328 	ret = nn_init(&u1, 0); EG(ret, err);
329 	ret = nn_init(&u2, 0); EG(ret, err);
330 
331 	/* Compute v = z ** (q-2) mod (q) in s */
332 	ret = nn_dec(&u1, q); EG(ret, err); /* use u1 as temp here */
333 	ret = nn_dec(&u1, &u1); EG(ret, err);
334 	ret = _nn_mod_pow_insecure(&v, &z, &u1, q); EG(ret, err);
335 	/* u1 = (s * v) mod q */
336 	ret = nn_mod_mul(&u1, &s, &v, q); EG(ret, err);
337 	/* u2 = ((q-r) * v) mod q */
338 	ret = nn_sub(&u2, q, &r); EG(ret, err);
339 	ret = nn_mod_mul(&u2, &u2, &v, q); EG(ret, err);
340 	/* Now compute v = ((g**u1 y**u2) mod p) mod q */
341 	/* NOTE: no need to use a secure exponentiation here as we only
342 	 * manipulate public data.
343 	 */
344 	ret = _nn_mod_pow_insecure(&v, g, &u1, p); EG(ret, err);
345 	ret = _nn_mod_pow_insecure(&s, y, &u2, p); EG(ret, err);
346 	ret = nn_mod_mul(&v, &v, &s, p); EG(ret, err);
347 	ret = nn_mod(&v, &v, q); EG(ret, err);
348 
349 	/* Check that v = r */
350 	ret = nn_cmp(&v, &r, &cmp); EG(ret, err);
351 	ret = (cmp != 0) ? -1 : 0;
352 
353 err:
354 	nn_uninit(&r);
355 	nn_uninit(&s);
356 	nn_uninit(&z);
357 	nn_uninit(&u1);
358 	nn_uninit(&u2);
359 	nn_uninit(&v);
360 
361 	PTR_NULLIFY(p);
362 	PTR_NULLIFY(q);
363 	PTR_NULLIFY(g);
364 	PTR_NULLIFY(y);
365 
366 	return ret;
367 }
368 
369 #ifdef GOSTR34_10_94
370 #include <libecc/utils/print_buf.h>
main(int argc,char * argv[])371 int main(int argc, char *argv[])
372 {
373  	int ret = 0;
374 
375 	/**** Self-signed certificate taken from RFC4491 ****/
376 	/* NOTE1: we can only perform verification using this self-signed certificate as we do not have the private key!
377 	 * NOTE2: id-GostR3410-94-CryptoPro-A-ParamSet (values of p, q, g) are extracted from the same RFC
378 	 */
379 	const u8 p[] = {
380 		0x00, 0xB4, 0xE2, 0x5E, 0xFB, 0x01, 0x8E, 0x3C, 0x8B, 0x87, 0x50, 0x5E, 0x2A, 0x67, 0x55, 0x3C,
381 		0x5E, 0xDC, 0x56, 0xC2, 0x91, 0x4B, 0x7E, 0x4F, 0x89, 0xD2, 0x3F, 0x03, 0xF0, 0x33, 0x77, 0xE7,
382 		0x0A, 0x29, 0x03, 0x48, 0x9D, 0xD6, 0x0E, 0x78, 0x41, 0x8D, 0x3D, 0x85, 0x1E, 0xDB, 0x53, 0x17,
383 		0xC4, 0x87, 0x1E, 0x40, 0xB0, 0x42, 0x28, 0xC3, 0xB7, 0x90, 0x29, 0x63, 0xC4, 0xB7, 0xD8, 0x5D,
384 		0x52, 0xB9, 0xAA, 0x88, 0xF2, 0xAF, 0xDB, 0xEB, 0x28, 0xDA, 0x88, 0x69, 0xD6, 0xDF, 0x84, 0x6A,
385 		0x1D, 0x98, 0x92, 0x4E, 0x92, 0x55, 0x61, 0xBD, 0x69, 0x30, 0x0B, 0x9D, 0xDD, 0x05, 0xD2, 0x47,
386 		0xB5, 0x92, 0x2D, 0x96, 0x7C, 0xBB, 0x02, 0x67, 0x18, 0x81, 0xC5, 0x7D, 0x10, 0xE5, 0xEF, 0x72,
387 		0xD3, 0xE6, 0xDA, 0xD4, 0x22, 0x3D, 0xC8, 0x2A, 0xA1, 0xF7, 0xD0, 0x29, 0x46, 0x51, 0xA4, 0x80,
388 		0xDF,
389 	};
390 
391 	const u8 q[] = {
392 		0x00,  0x97,  0x24,  0x32,  0xA4,  0x37,  0x17,  0x8B,  0x30,  0xBD,  0x96,  0x19,  0x5B,  0x77,  0x37,  0x89,
393 		0xAB,  0x2F,  0xFF,  0x15,  0x59,  0x4B,  0x17,  0x6D,  0xD1,  0x75,  0xB6,  0x32,  0x56,  0xEE,  0x5A,  0xF2,
394 		0xCF,
395 	};
396 
397 	const u8 g[] = {
398 		0x00,  0x8F,  0xD3,  0x67,  0x31,  0x23,  0x76,  0x54,  0xBB,  0xE4,  0x1F,  0x5F,  0x1F,  0x84,  0x53,  0xE7,
399 		0x1C,  0xA4,  0x14,  0xFF,  0xC2,  0x2C,  0x25,  0xD9,  0x15,  0x30,  0x9E,  0x5D,  0x2E,  0x62,  0xA2,  0xA2,
400 		0x6C,  0x71,  0x11,  0xF3,  0xFC,  0x79,  0x56,  0x8D,  0xAF,  0xA0,  0x28,  0x04,  0x2F,  0xE1,  0xA5,  0x2A,
401 		0x04,  0x89,  0x80,  0x5C,  0x0D,  0xE9,  0xA1,  0xA4,  0x69,  0xC8,  0x44,  0xC7,  0xCA,  0xBB,  0xEE,  0x62,
402 		0x5C,  0x30,  0x78,  0x88,  0x8C,  0x1D,  0x85,  0xEE,  0xA8,  0x83,  0xF1,  0xAD,  0x5B,  0xC4,  0xE6,  0x77,
403 		0x6E,  0x8E,  0x1A,  0x07,  0x50,  0x91,  0x2D,  0xF6,  0x4F,  0x79,  0x95,  0x64,  0x99,  0xF1,  0xE1,  0x82,
404 		0x47,  0x5B,  0x0B,  0x60,  0xE2,  0x63,  0x2A,  0xDC,  0xD8,  0xCF,  0x94,  0xE9,  0xC5,  0x4F,  0xD1,  0xF3,
405 		0xB1,  0x09,  0xD8,  0x1F,  0x00,  0xBF,  0x2A,  0xB8,  0xCB,  0x86,  0x2A,  0xDF,  0x7D,  0x40,  0xB9,  0x36,
406 		0x9A,
407 	};
408 
409 	u8 x[sizeof(q)];
410 
411 	u8 y_self_signed[] = {
412 		0xBB, 0x84, 0x66, 0xE1, 0x79, 0x9E, 0x5B, 0x34, 0xD8, 0x2C, 0x80, 0x7F, 0x13, 0xA8, 0x19, 0x66,
413 		0x71, 0x57, 0xFE, 0x8C, 0x54, 0x25, 0x21, 0x47, 0x6F, 0x30, 0x0B, 0x27, 0x77, 0x46, 0x98, 0xC6,
414 		0xFB, 0x47, 0x55, 0xBE, 0xB7, 0xB2, 0xF3, 0x93, 0x6C, 0x39, 0xB5, 0x42, 0x37, 0x26, 0x84, 0xE2,
415 		0x0D, 0x10, 0x8A, 0x24, 0x0E, 0x1F, 0x0C, 0x42, 0x4D, 0x2B, 0x3B, 0x11, 0x2B, 0xA8, 0xBF, 0x66,
416 		0x39, 0x32, 0x5C, 0x94, 0x8B, 0xC1, 0xA8, 0xFE, 0x1B, 0x63, 0x12, 0xF6, 0x09, 0x25, 0x87, 0xCC,
417 		0x75, 0x1B, 0xF4, 0xE5, 0x89, 0x8A, 0x09, 0x82, 0x68, 0xD3, 0x5C, 0x77, 0xA6, 0x0F, 0xB6, 0x90,
418 		0x10, 0x13, 0x8D, 0xE3, 0x3E, 0x7C, 0x9C, 0x91, 0xD6, 0xAC, 0x0D, 0x08, 0x2C, 0x3E, 0x78, 0xC1,
419 		0xB5, 0xC2, 0xB6, 0xB7, 0x1A, 0xA8, 0x2A, 0x8B, 0x45, 0x81, 0x93, 0x32, 0x32, 0x76, 0xFA, 0x7B,
420 	};
421 
422 	const u8 sig[32*2] = {
423 		/* r' */
424 		0x22, 0xf7, 0x85, 0xf3,	0x55, 0xbd, 0x94, 0xec, 0x46, 0x91, 0x9c, 0x67, 0xac, 0x58, 0xd7, 0x05, 0x2a, 0xa7,
425 		0x8c, 0xb7, 0x85, 0x2a, 0x01, 0x75, 0x85, 0xf7, 0xd7, 0x38, 0x03, 0xfb, 0xcd, 0x43,
426 		/* s */
427 		0x11, 0xc7, 0x08, 0x7e, 0x12, 0xdc, 0x02, 0xf1, 0x02, 0x23, 0x29, 0x47, 0x76, 0x8f, 0x47, 0x2a, 0x81, 0x83,
428 		0x50, 0xe3, 0x07, 0xcc, 0xf2, 0xe4, 0x31, 0x23, 0x89, 0x42, 0xc8, 0x73, 0xe1, 0xde,
429 	};
430 	u8 check_sig[32*2];
431 
432 	const u8 msg[] = {
433 		0x30, 0x82, 0x01, 0xba, 0x02, 0x10, 0x23, 0x0e, 0xe3, 0x60, 0x46, 0x95,
434 		0x24, 0xce, 0xc7, 0x0b, 0xe4, 0x94, 0x18, 0x2e, 0x7e, 0xeb, 0x30, 0x08,
435 		0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x04, 0x30, 0x69, 0x31, 0x1d,
436 		0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x47, 0x6f, 0x73,
437 		0x74, 0x52, 0x33, 0x34, 0x31, 0x30, 0x2d, 0x39, 0x34, 0x20, 0x65, 0x78,
438 		0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
439 		0x04, 0x0a, 0x0c, 0x09, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x50, 0x72,
440 		0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
441 		0x52, 0x55, 0x31, 0x27, 0x30, 0x25, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
442 		0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x18, 0x47, 0x6f, 0x73, 0x74, 0x52,
443 		0x33, 0x34, 0x31, 0x30, 0x2d, 0x39, 0x34, 0x40, 0x65, 0x78, 0x61, 0x6d,
444 		0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30,
445 		0x35, 0x30, 0x38, 0x31, 0x36, 0x31, 0x32, 0x33, 0x32, 0x35, 0x30, 0x5a,
446 		0x17, 0x0d, 0x31, 0x35, 0x30, 0x38, 0x31, 0x36, 0x31, 0x32, 0x33, 0x32,
447 		0x35, 0x30, 0x5a, 0x30, 0x69, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55,
448 		0x04, 0x03, 0x0c, 0x14, 0x47, 0x6f, 0x73, 0x74, 0x52, 0x33, 0x34, 0x31,
449 		0x30, 0x2d, 0x39, 0x34, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
450 		0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x43,
451 		0x72, 0x79, 0x70, 0x74, 0x6f, 0x50, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09,
452 		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x55, 0x31, 0x27, 0x30,
453 		0x25, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
454 		0x16, 0x18, 0x47, 0x6f, 0x73, 0x74, 0x52, 0x33, 0x34, 0x31, 0x30, 0x2d,
455 		0x39, 0x34, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63,
456 		0x6f, 0x6d, 0x30, 0x81, 0xa5, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 0x03,
457 		0x02, 0x02, 0x14, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
458 		0x20, 0x02, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01, 0x03,
459 		0x81, 0x84, 0x00, 0x04, 0x81, 0x80, 0xbb, 0x84, 0x66, 0xe1, 0x79, 0x9e,
460 		0x5b, 0x34, 0xd8, 0x2c, 0x80, 0x7f, 0x13, 0xa8, 0x19, 0x66, 0x71, 0x57,
461 		0xfe, 0x8c, 0x54, 0x25, 0x21, 0x47, 0x6f, 0x30, 0x0b, 0x27, 0x77, 0x46,
462 		0x98, 0xc6, 0xfb, 0x47, 0x55, 0xbe, 0xb7, 0xb2, 0xf3, 0x93, 0x6c, 0x39,
463 		0xb5, 0x42, 0x37, 0x26, 0x84, 0xe2, 0x0d, 0x10, 0x8a, 0x24, 0x0e, 0x1f,
464 		0x0c, 0x42, 0x4d, 0x2b, 0x3b, 0x11, 0x2b, 0xa8, 0xbf, 0x66, 0x39, 0x32,
465 		0x5c, 0x94, 0x8b, 0xc1, 0xa8, 0xfe, 0x1b, 0x63, 0x12, 0xf6, 0x09, 0x25,
466 		0x87, 0xcc, 0x75, 0x1b, 0xf4, 0xe5, 0x89, 0x8a, 0x09, 0x82, 0x68, 0xd3,
467 		0x5c, 0x77, 0xa6, 0x0f, 0xb6, 0x90, 0x10, 0x13, 0x8d, 0xe3, 0x3e, 0x7c,
468 		0x9c, 0x91, 0xd6, 0xac, 0x0d, 0x08, 0x2c, 0x3e, 0x78, 0xc1, 0xb5, 0xc2,
469 		0xb6, 0xb7, 0x1a, 0xa8, 0x2a, 0x8b, 0x45, 0x81, 0x93, 0x32, 0x32, 0x76,
470 		0xfa, 0x7b
471 	};
472 
473 	gostr34_10_94_pub_key pub;
474 	gostr34_10_94_priv_key priv;
475 	nn x_;
476 	x_.magic = WORD(0);
477 
478 	FORCE_USED_VAR(argc);
479 	FORCE_USED_VAR(argv);
480 
481 	/* Sanity check on size for GOSTR34_10_94.
482 	 * NOTE: the double parentheses are here to handle -Wunreachable-code
483 	 */
484 	if((NN_USABLE_MAX_BIT_LEN) < (4096)){
485 		ext_printf("Error: you seem to have compiled libecc with usable NN size < 4096, not suitable for GOSTR34_10_94.\n");
486 		ext_printf("  => Please recompile libecc with EXTRA_CFLAGS=\"-DUSER_NN_BIT_LEN=4096\"\n");
487 		ext_printf("     This will increase usable NN for proper GOSTR34_10_94 up to 4096 bits.\n");
488 		ext_printf("     Then recompile the current examples with the same EXTRA_CFLAGS=\"-DUSER_NN_BIT_LEN=4096\" flag and execute again!\n");
489 		/* NOTE: ret = 0 here to pass self tests even if the library is not compatible */
490 		ret = 0;
491 		goto err;
492 	}
493 
494 	/* Reverse the endianness of y in place as it is little endian encoded */
495 	ret = _reverse_endianness(&y_self_signed[0], sizeof(y_self_signed)); EG(ret, err);
496 
497 	ret = gostr34_10_94_import_pub_key(&pub, p, sizeof(p), q, sizeof(q), g, sizeof(g), y_self_signed, sizeof(y_self_signed)); EG(ret, err);
498 
499 	/* Verify the signature */
500 	ret = gostr34_10_94_verify(&pub, msg, sizeof(msg), sig, sizeof(sig), HASH_GOST34_11_94_RFC4357);
501 	ext_printf("RFC4357 self-signed signature result %d\n", ret);
502 
503 	/****** Now check the signature procedure *********/
504 	/* Get a random private key 0 < x < q */
505 	ret = nn_get_random_mod(&x_, &(pub.q)); EG(ret, err);
506 	ret = _i2osp(&x_, &x[0], sizeof(x)); EG(ret, err);
507 	/* Import the private key */
508 	ret = gostr34_10_94_import_priv_key(&priv, p, sizeof(p), q, sizeof(q), g, sizeof(g), x, sizeof(x)); EG(ret, err);
509 	/* Compute the public key from the private key */
510 	ret = gostr34_10_94_compute_pub_from_priv(&pub, &priv); EG(ret, err);
511 	/* Sign the message */
512 	ret = gostr34_10_94_sign(&priv, msg, sizeof(msg), NULL, 0, check_sig, sizeof(check_sig), HASH_GOST34_11_94_RFC4357); EG(ret, err);
513 	/* Verify the message */
514 	ret = gostr34_10_94_verify(&pub, msg, sizeof(msg), check_sig, sizeof(check_sig), HASH_GOST34_11_94_RFC4357);
515 	ext_printf("Random signature result %d\n", ret);
516 
517 err:
518 	nn_uninit(&x_);
519 	return ret;
520 }
521 #endif
522