MPHELL  4.0.0
mphell_tuto_ecdsa_fips.c
Go to the documentation of this file.
1 /*
2  MPHELL-4.0
3  Author(s): The MPHELL team
4 
5  (C) Copyright 2015-2018 - Institut Fourier / Univ. Grenoble Alpes (France)
6 
7  This file is part of the MPHELL Library.
8  MPHELL is free software: you can redistribute it and/or modify
9  it under the terms of the GNU Lesser General Public License as published by
10  the Free Software Foundation, version 3 of the License.
11 
12  MPHELL is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public License
18  along with MPHELL. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
42 #include <stdio.h>
43 #include "mphell/mphell.h"
44 #if MPHELL_USE_MULTITHREADING == 1
45 #include <omp.h>
46 #endif
47 
52 struct ecdsa_sig
53 {
54  number *r;
55  number *s;
56 };
57 
62 typedef struct ecdsa_sig ecdsa_sig_t;
63 
68 typedef ecdsa_sig_t ecdsa_sig[1];
69 
76 void
77 ecdsa_sign_alloc(ecdsa_sig *sig, uint8_t size)
78 {
79  (*sig)->r = (number*)malloc(sizeof(number));
80  (*sig)->s = (number*)malloc(sizeof(number));
81  number_init((*sig)->r, size);
82  number_init((*sig)->s, size);
83  number_set_ui(*((*sig)->r), (block)0);
84  number_set_ui(*((*sig)->s), (block)0);
85 }
86 
92 void
94 {
95  if ((*sig)->r)
96  {
97  number_free((*sig)->r);
98  free((*sig)->r);
99  }
100  if ((*sig)->s)
101  {
102  number_free((*sig)->s);
103  free((*sig)->s);
104  }
105 }
106 
117 void
118 ec_point_mul_ecdsa(ec_point dst, number_srcptr u1, ec_point_srcptr G,
119  number_srcptr u2, ec_point_srcptr key, ec_curve_srcptr E)
120 {
121 #if MPHELL_USE_MULTITHREADING == 1
122  omp_set_num_threads(2);
123  ec_point tmp;
124  ec_point_get_pool_elt(tmp, E->k, STACK_1);
125  #pragma omp parallel
126  {
127  #pragma omp sections
128  {
129  #pragma omp section
130  {
131  ec_point_mul(tmp, u2, key, E, STACK_1);
132  }
133  #pragma omp section
134  {
135  ec_point_mul(dst, u1, G, E, STACK_2);
136  }
137  }
138  }
139  ec_point_add(dst, dst, tmp, E, STACK_1);
140  ec_point_relax_pool_elt(tmp, E->k, STACK_1);
141 #else
142  ec_point tmp;
143  ec_point_get_pool_elt(tmp, E->k, STACK_1);
144  ec_point_mul(tmp, u2, key, E, STACK_1);
145  ec_point_mul(dst, u1, G, E, STACK_1);
146  ec_point_add(dst, dst, tmp, E, STACK_1);
147  ec_point_relax_pool_elt(tmp, E->k, STACK_1);
148 #endif
149 }
150 
159 void
160 ecdsa_sign(unsigned char *hash, ecdsa_sig *sig, number_ptr priv_key, ec_curve *curve)
161 {
163  number *rr = (*sig)->r;
164  number *ss = (*sig)->s;
165 
166  uint8_t size = (*curve)->k->size;
167 
168  number k; number_tmp_alloc(&k, size, STACK_1);
169  number h; number_tmp_alloc(&h, (strlen((char *)hash)/(BLOCK_SIZE/4)), STACK_1);
170  number t; number_tmp_alloc(&t, size, STACK_1);
171  number tt; number_tmp_alloc(&tt, 2*size+1, STACK_1);
172 
173  number abs;
174  number_tmp_alloc(&abs, size, STACK_1);
175 
176  ec_point x;
177  ec_point_get_pool_elt(x, (*curve)->k, STACK_1);
178 
179  field_elt xx;
180  field_elt_get_pool_elt(&xx, (*curve)->k, STACK_1);
181 
182  bool newk = true;
183  number_set_str(h , (char*)hash, 16);
184 
185  while(newk)
186  {
187  /* Choose k randomly in [1, n-1] */
188  number_random1(k, (*curve)->n, STACK_1);
189 
190  /* Compute (x,y) = kG */
191  ec_point_mul_unified(x, k, (*curve)->G, *curve, STACK_1);
192  ec_point_get_x_affine(xx, x, *curve, STACK_1);
193 
194  /* r = x mod n */
195  field_elt_get_number(abs, xx, 1, (*curve)->k, STACK_1);
196  number_mod(*rr, abs, (*curve)->n);
197 
198  /* if r == 0 --> new k */
199  if(!number_iszero(*rr))
200  {
201  /* s = k^-1 (hash + r*priv_key) mod n */
202  number_mul(tt, *rr, priv_key);
203  number_add(tt, tt, h);
204  number_mod(tt, tt, (*curve)->n); /* To keep the multiplication small */
205  number_invmod(t, k, (*curve)->n);
206  number_mul(tt, tt, t);
207  number_mod(*ss, tt, (*curve)->n);
208 
209  /* if s == 0 --> new k */
210  if(!number_iszero(*ss))
211  {
212  newk = false;
213  }
214  }
215  }
216  (*sig)->r = rr;
217  (*sig)->s = ss;
218 
219  /* Free memory */
220  ec_point_relax_pool_elt(x, (*curve)->k, STACK_1);
221  field_elt_relax_pool_elt(&xx, (*curve)->k, STACK_1);
222  number_tmp_free(&tt, 2*size+1, STACK_1);
223  number_tmp_free(&t, size, STACK_1);
224  number_tmp_free(&h, (strlen((char *)hash)/(BLOCK_SIZE/4)), STACK_1);
225  number_tmp_free(&k, size, STACK_1);
226  number_tmp_free(&abs, size, STACK_1);
227 }
228 
229 
230 /* For the hash several functions can be used, the interested reader can refer to [FIPS-180] */
231 
241 int8_t
242 ecdsa_verify(unsigned char *hash, ecdsa_sig *sig, ec_point *pub_key, ec_curve *curve)
243 {
245 
246  if( number_iszero(*((*sig)->r)) || number_cmp(*((*sig)->r),(*curve)->n)>=0 || number_iszero(*((*sig)->s)) || number_cmp(*((*sig)->s),(*curve)->n)>=0)
247  {
248  return false;
249  }
250  uint8_t size = (*curve)->k->size;
251 
252  number w; number_tmp_alloc(&w, size, STACK_1);
253  number u1; number_tmp_alloc(&u1, size, STACK_1);
254  number u2; number_tmp_alloc(&u2, size, STACK_1);
255  number tt2; number_tmp_alloc(&tt2, 2*size, STACK_1);
256 
257  number abs;
258  number_tmp_alloc(&abs, size, STACK_1);
259 
260  ec_point x;
261  ec_point_get_pool_elt(x, (*curve)->k, STACK_1);
262  number h; number_tmp_alloc(&h, (strlen((char *)hash)/(BLOCK_SIZE/4)), STACK_1);
263  number_set_str(h , (char*)hash, 16);
264 
265  field_elt xx;
266  field_elt_get_pool_elt(&xx, (*curve)->k, STACK_1);
267 
268  /* w = s^-1 mod n */
269  number_invmod(w, *((*sig)->s), (*curve)->n);
270 
271  /* u1 = hash * w mod n */
272  number_mod(u1, h, (*curve)->n);
273  number_mul(tt2, u1, w);
274  number_mod(u1, tt2, (*curve)->n);
275 
276  /* u2 = r*w mod n */
277  number_mul(tt2, *((*sig)->r), w);
278  number_mod(u2, tt2, (*curve)->n);
279 
280  /* x = u1*G + u2*Q */
281  ec_point_mul_ecdsa(x, u1, (*curve)->G, u2, *pub_key, *curve);
282  ec_point_get_x_affine(xx, x, *curve, STACK_1);
283 
284  /* Get the result, by comparing x value with r */
285  field_elt_get_number(abs, xx, 1, (*curve)->k, STACK_1);
286  number_mod(w, abs, (*curve)->n);
287  bool result = number_cmp(w, *((*sig)->r)) == 0;
288 
289  /* Free memory */
290  number_tmp_free(&h, (strlen((char *)hash)/(BLOCK_SIZE/4)), STACK_1);
291  ec_point_relax_pool_elt(x, (*curve)->k, STACK_1);
292  field_elt_relax_pool_elt(&xx, (*curve)->k, STACK_1);
293  number_tmp_free(&tt2, 2*size, STACK_1);
294  number_tmp_free(&u2, size, STACK_1);
295  number_tmp_free(&u1, size, STACK_1);
296  number_tmp_free(&w, size, STACK_1);
297  number_tmp_free(&abs, size, STACK_1);
298 
299  return result;
300 }
301 
310 int8_t
312 {
313  if(!ec_belongs(*pub_key, *curve, STACK_1))
314  {
315  /* pubkey does not belong to the curve */
316  return false;
317  }
318  if(ec_point_is_neutral(*pub_key, *curve, STACK_1))
319  {
320  /* pubkey is the neutral element */
321  return false;
322  }
323  /* We finally test the order of the curve */
324  ec_point x;
325  ec_point_get_pool_elt(x, (*curve)->k, STACK_1);
326  ec_point_mul(x, (*curve)->n, *pub_key, *curve, STACK_1);
327  if(!ec_point_is_neutral(x, *curve, STACK_1))
328  {
329  /* pubkey is the neutral element */
330  return false;
331  }
332  ec_point_relax_pool_elt(x, (*curve)->k, STACK_1);
333 
334  return true;
335 }
336 
337 int main()
338 {
339  /* Initialise MPHELL with 256 bits of security strength for the entropy, RANDOM_AES256 as DRBG and DEVURANDOM as entropy source */
340 
342 
343  /* Allocate a field of size 4*block_SIZE = 4*64 = 256 on 64 bits architecture */
344 
345  field k;
346  field_alloc(k, FP, bits_to_nblock(256), NULL);
347 
348  /* Allocate a number of size 4*block_SIZE = 4*64 = 256 on 64 bits architecture */
349 
350  number p;
351  number_init(&p, bits_to_nblock(256));
352 
353  /* Set the number p from a string in base 16 */
354 
355  number_set_str(p, "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16);
356 
357  /* Create the field of characteristic p */
358 
359  field_create(k, "", STACK_1, 1, p);
360 
361  /* Allocate curve */
362 
363  ec_curve E;
364  ec_alloc (E, k);
365  ec_init(E, k);
366 
367  /* Create curve */
368 
369  field_elt a, b;
370  ec_point G;
371  number n, h;
372 
373  field_elt_alloc(&a, k);
374  field_elt_init(a, k);
375  field_elt_alloc(&b, k);
376  field_elt_init(b, k);
377  ec_point_alloc(G, k);
378  ec_point_init(G, k);
379  number_init(&n, bits_to_nblock(256));
380  number_init(&h, bits_to_nblock(256));
381 
382  field_elt_set_str(a, "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16, false, k, STACK_1);
383  field_elt_set_str(b, "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16, false, k, STACK_1);
384  ec_point_set_aff_str(G, "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", false, 16, WEIERSTRASS, k, STACK_1);
385  number_set_str(h, "1", 16);
386  number_set_str(n, "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16);
387 
388  ec_create (E, "Weierstrass_nist_256", k, a, b, G, h, n, WEIERSTRASS, JACOBIAN, STACK_1);
389 
390  printf("E: \n"); ec_curve_print(E, 16, STACK_1); printf("\n");
391 
392  field_elt_free(&a, k);
393  field_elt_free(&b, k);
394  ec_point_free(G, k);
395  number_free(&h);
396  number_free(&n);
397 
398  /* Get private key from random value between 0 and the size of the group generated by G:E->n */
399  number priv_key;
400  number_init(&priv_key, bits_to_nblock(256));
401  number_random1(priv_key, E->n, STACK_1);
402 
403  /* Test that the value is not equal to p-1 and change it until it is the case */
404  number test;
405  number_init(&test, bits_to_nblock(256));
406  number_dec(test, E->n);
407  while(number_cmp(test, priv_key)<=0)
408  {
409  number_random1(priv_key, E->n, STACK_1);
410  }
411  number_free(&test);
412  number_inc(priv_key, priv_key);
413  printf("\nThe private key has been created its value is:\n");
414  number_print(priv_key, 16);
415 
416  /* Computation of the public key */
417  ec_point pub_key;
418  ec_point_alloc(pub_key, E->k);
419  ec_point_init(pub_key, E->k);
420  ec_point_mul_unified(pub_key, priv_key, E->G, E, STACK_1);
421 
422  /* Print the public key */
423  ec_point_norm(pub_key, E, STACK_1);
424  printf("\nThe pubkey has been computed:\n");
425  ec_point_print(pub_key, 16, true, k, STACK_1);
426 
427  /* This test is optional.*/
428  printf("\nThe validity of the public key is a:\n");
429  int ret = ecdsa_pub_key_validation(&pub_key, &E);
430  if( ret < 1 )
431  {
432  printf("ERROR\n");
433  }
434  else
435  {
436  printf("SUCCESS\n");
437  }
438 
439  /* Digest to sign */
440  char * digest = "982c20c2493fc9ae405b74b65a022662c014a38ef3d707217e56e57afac05994";
441 
442  /* Allocate ecdsa_sig structure */
443  ecdsa_sig sig;
444  ecdsa_sign_alloc(&sig, bits_to_nblock(256));
445 
446  /* Sign the digest */
447  ecdsa_sign((unsigned char *)digest, &sig, priv_key, &E);
448 
449  printf("\nThe ECDSA signature is: (");
450  number_print(*(sig->r), 16);
451  printf(", ");
452  number_print(*(sig->s), 16);
453  printf(")\n");
454 
455  /* Verify the signature */
456  printf("\n-> Verify ECDSA signature \n");
457  ret = ecdsa_verify((unsigned char *)digest, &sig, &pub_key, &E);
458  if( ret < 1 )
459  {
460  printf("ERROR\n");
461  }
462  else
463  {
464  printf("SUCCESS\n");
465  }
466 
467  /* Free memory */
468 
469  ec_point_free(pub_key, k);
470  number_free(&priv_key);
471  ecdsa_sign_free(&sig);
472  number_free(&p);;
473  field_free(k);
474  ec_free(E);
475 
476  free_mphell();
477 
478  return 0;
479 }
bool ec_belongs(ec_point_srcptr P, ec_curve_srcptr E, uint8_t stack)
Test if P belongs to E.
Definition: mphell-curve.c:865
bool number_iszero(number_srcptr src)
Test if src is zero.
fp_elt * field_elt
Generic field element.
Definition: mphell-field.h:39
void free_mphell()
Free MPHELL memory, especially the big amount of temporary memory.
Definition: mphell-init.c:97
void ec_create(ec_curve_ptr E, const char *id_curve, field_srcptr k, fe_srcptr a, fe_srcptr b, ec_point_srcptr G, number_srcptr h, number_srcptr n, const ec_type type, const ec_formula f, uint8_t stack)
Create an elliptic curve E, the curve must be allocated and initialised (ec_alloc & ec_init)
Definition: mphell-curve.c:62
void field_elt_free(fe_ptr *src, field_srcptr k)
Free space used by src.
Definition: mphell-field.c:356
void ecdsa_sign(unsigned char *hash, ecdsa_sig *sig, number_ptr priv_key, ec_curve *curve)
Sign "hash" with ECDSA algorithm using the EC "curve" and the private key "key".
void number_invmod(number_ptr dst, number_srcptr src1, number_srcptr src2)
Compute dst such that dst = src1^(-1) mod src2.
void init_mphell(const uint16_t security_strength, const random_type type, const entropy_type entropy)
Initialise MPHELL with security_strength bits of security (for random number only).
Definition: mphell-init.c:35
Define an elliptic curve point.
Definition: mphell-curve.h:103
void ec_point_alloc(ec_point_ptr P, field_srcptr k)
Allocate an elliptic curve point.
Definition: mphell-curve.c:673
void number_set_ui(number_ptr dst, const block src)
Set dst to src.
void ec_init(ec_curve_ptr E, field_srcptr k)
Initialise a curve.
Definition: mphell-curve.c:52
void ec_point_print(ec_point_srcptr P, const uint8_t base, const bool lift, field_srcptr k, uint8_t stack)
Print a description of P.
uint8_t bits_to_nblock(const uint16_t nbits)
Return the number of blocks required to store a nbits number.
Definition: mphell-util.c:29
void field_elt_alloc(fe_ptr *dst, field_srcptr k)
Allocate space for a field element.
Definition: mphell-field.c:277
void ec_point_init(ec_point_ptr P, field_srcptr k)
Initialise an elliptic curve point.
Definition: mphell-curve.c:682
field_t field[1]
Address of a field structure.
Definition: mphell-field.h:110
void ec_point_add(ec_point_ptr P3, ec_point_srcptr P1, ec_point_srcptr P2, ec_curve_srcptr E, uint8_t stack)
Set P3 to P1 + P2, using dedicated formulae (not protected against SPA, but faster)
void number_random1(number_ptr dst, number_srcptr bound, uint8_t stack)
Set dst to a random number_ptr between 0 and bound, the random process is chosen at the MPHELL initia...
void number_free(number *dst)
Free a number_ptr allocated on the RAM memory (malloc)
Definition: mphell-number.c:75
void ec_point_free(ec_point_ptr P, field_srcptr k)
Free the point P.
Definition: mphell-curve.c:700
void ec_free(ec_curve_ptr E)
Free the elliptic curve E.
Definition: mphell-curve.c:655
static void ec_point_relax_pool_elt(ec_point_ptr P, field_ptr k, uint8_t stack)
Relax an initialised point from the pool.
Definition: mphell-curve.h:218
void ec_point_mul_ecdsa(ec_point dst, number_srcptr u1, ec_point_srcptr G, number_srcptr u2, ec_point_srcptr key, ec_curve_srcptr E)
Compute u1 * G + u2 * key.
bool ec_point_is_neutral(ec_point_srcptr P, ec_curve_srcptr E, uint8_t stack)
Test if P is the neutral element.
void field_create(field_ptr k, const char *id, uint8_t stack, const uint32_t n,...)
Initialize the different fields of the structure pointed by k.
Definition: mphell-field.c:76
void field_elt_get_number(number_ptr dst, fe_srcptr src, uint8_t pos, field_srcptr k, uint8_t stack)
If Montgomery arithmetic is used, lift src (which is into Montgomery form) to classical fp (or its co...
Definition: mphell-field.c:563
void ecdsa_sign_free(ecdsa_sig *sig)
Free a used signature structure.
void ec_point_set_aff_str(ec_point_ptr P, const char *str_x, const char *str_y, const bool is_reduced, const uint8_t base, const ec_type type, field_srcptr k, uint8_t stack)
Set a point from its affine coordinates under string format.
Definition: mphell-curve.c:759
static void ec_point_get_pool_elt(ec_point_ptr P, field_ptr k, uint8_t stack)
Get an initialised point from the pool.
Definition: mphell-curve.h:202
void number_mul(number_ptr dst, number_srcptr src1, number_srcptr src2)
Set dst to src1 * src2.
void ecdsa_sign_alloc(ecdsa_sig *sig, uint8_t size)
Allocate a signature structure.
void ec_alloc(ec_curve_ptr E, field_srcptr k)
Allocate a curve.
Definition: mphell-curve.c:37
void ec_set_fast_unified_coordinates(ec_curve_ptr E)
Set the fastest unified coordinates system.
Definition: mphell-curve.c:544
void field_alloc(field_ptr k, const field_type type, const uint8_t size, field_ptr base)
Allocates space for the different fields of the structure pointed by k.
Definition: mphell-field.c:37
number n
Definition: mphell-curve.h:148
void number_tmp_free(number *t, const uint8_t size, uint8_t stack)
Free a temporary number.
Definition: mphell-number.c:45
void ec_point_mul(ec_point_ptr P3, number_srcptr n, ec_point_srcptr P1, ec_curve_srcptr E, uint8_t stack)
Set P3 to n * P1 using Montgomery for Weierstrass elliptic curve, and naive method for other elliptic...
ec_point G
Definition: mphell-curve.h:147
void field_elt_init(fe_ptr dst, field_srcptr k)
Initialise the field element.
Definition: mphell-field.c:299
void number_dec(number_ptr dst, number_srcptr src)
Set dst to src - 1 if src - 1 fit in dst.
void number_inc(number_ptr dst, number_srcptr src)
Set dst to src + 1 if src + 1 fit in dst.
Define an ECDSA signature.
void ec_curve_print(ec_curve_srcptr E, const uint8_t base, uint8_t stack)
Print a description of E.
void number_add(number_ptr dst, number_srcptr src1, number_srcptr src2)
Set dst to src1 + src2 if src1 + src2 fit in dst.
field_ptr k
Definition: mphell-curve.h:142
void number_set_str(number_ptr dst, const char *str, const uint8_t base)
Set dst to str.
void number_tmp_alloc(number *t, const uint8_t size, uint8_t stack)
Allocate a temporary number.
Definition: mphell-number.c:31
void number_init(number *dst, const uint8_t n)
Allocate a number_ptr on the RAM memory (malloc)
Definition: mphell-number.c:59
int8_t number_cmp(number_srcptr src1, number_srcptr src2)
Compare src1 and src2.
void field_free(field_ptr k)
Free the space of the field informations structure.
Definition: mphell-field.c:183
void number_print(number_srcptr src, const uint8_t base)
Print src in base "base".
Define an elliptic curve.
Definition: mphell-curve.h:139
int8_t ecdsa_pub_key_validation(ec_point *pub_key, ec_curve *curve)
Verify that the public key is valid (id est check taht pub_key belongs to the curve,...
void number_mod(number_ptr dst, number_srcptr src1, number_srcptr src2)
Compute dst such that src1 = q * src2 + dst ; dst < src2.
void field_elt_set_str(fe_ptr dst, const char *str, const uint8_t base, const bool isreduced, field_srcptr k, uint8_t stack)
Set dst to str, if Montgomery arithmetic is used, is_reduced == false -> transform dst into its Montg...
Definition: mphell-field.c:505
int8_t ecdsa_verify(unsigned char *hash, ecdsa_sig *sig, ec_point *pub_key, ec_curve *curve)
Verify the signature "sig" of hash "hash" using public key "pub_key" and the EC "curve".
static void field_elt_relax_pool_elt(field_elt *dst, field_ptr k, uint8_t stack)
Relax an initialised field element from the pool.
Definition: mphell-field.h:167
void ec_set_fast_dedicated_coordinates(ec_curve_ptr E)
Set the fastest dedicated coordinates system.
Definition: mphell-curve.c:562
static void field_elt_get_pool_elt(field_elt *dst, field_ptr k, uint8_t stack)
Get an initialised field element from the pool.
Definition: mphell-field.h:134
void ec_point_norm(ec_point_ptr P, ec_curve_srcptr E, uint8_t stack)
Convert a point in projective or jacobian coordinate to an affine point (x,y)
Definition: mphell-curve.c:799
void ec_point_get_x_affine(field_elt x, ec_point_ptr P, ec_curve_srcptr E, uint8_t stack)
Convert P->x to its affine representation.
Definition: mphell-curve.c:818
void ec_point_mul_unified(ec_point_ptr P3, number_srcptr n, ec_point_srcptr P1, ec_curve_srcptr E, uint8_t stack)
Set P3 to n * P1 using Montgomery for Weierstrass elliptic curve, and naive method for other elliptic...