corrected copyright notices
[gnutls.git] / lib / nettle / ecc_mulmod.c
blob782113a49c7f17805ef5de761e27942f6cf3c760
1 /*
2 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
4 * Author: Ilya Tumaykin
6 * This file is part of GNUTLS.
8 * The GNUTLS library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include "ecc.h"
27 Perform a point multiplication using wMNAF representation
28 @param k The scalar to multiply by
29 @param G The base point
30 @param R [out] Destination for kG
31 @param a The curve's A value
32 @param modulus The modulus of the field the ECC curve is in
33 @param map Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
34 @return GNUTLS_E_SUCCESS on success
36 int
37 ecc_mulmod (mpz_t k, ecc_point * G, ecc_point * R, mpz_t a,
38 mpz_t modulus, int map)
40 ecc_point *pos[WMNAF_PRECOMPUTED_LENGTH], *neg[WMNAF_PRECOMPUTED_LENGTH];
41 int i, j, err;
43 signed char *wmnaf = NULL;
44 size_t wmnaf_len;
45 signed char digit;
47 if (k == NULL || G == NULL || R == NULL || modulus == NULL)
48 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
50 /* alloc ram for precomputed values */
51 for (i = 0; i < WMNAF_PRECOMPUTED_LENGTH; ++i)
53 pos[i] = ecc_new_point ();
54 neg[i] = ecc_new_point ();
55 if (pos[i] == NULL || neg[i] == NULL)
57 for (j = 0; j < i; ++j)
59 ecc_del_point (pos[j]);
60 ecc_del_point (neg[j]);
63 return GNUTLS_E_MEMORY_ERROR;
67 /* fill in pos and neg arrays with precomputed values
68 * pos holds kG for k == 1, 3, 5, ..., (2^w - 1)
69 * neg holds kG for k == -1,-3,-5, ...,-(2^w - 1)
72 /* pos[0] == 2G for a while, later it will be set to the expected 1G */
73 if ((err = ecc_projective_dbl_point (G, pos[0], a, modulus)) != 0)
74 goto done;
76 /* pos[1] == 3G */
77 if ((err =
78 ecc_projective_add_point (pos[0], G, pos[1], a, modulus)) != 0)
79 goto done;
81 /* fill in kG for k = 5, 7, ..., (2^w - 1) */
82 for (j = 2; j < WMNAF_PRECOMPUTED_LENGTH; ++j)
84 if ((err =
85 ecc_projective_add_point (pos[j - 1], pos[0], pos[j], a,
86 modulus)) != 0)
87 goto done;
90 /* set pos[0] == 1G as expected
91 * after this step we don't need G at all
92 * and can change it without worries even if R == G */
93 mpz_set (pos[0]->x, G->x);
94 mpz_set (pos[0]->y, G->y);
95 mpz_set (pos[0]->z, G->z);
97 /* neg[i] == -pos[i] */
98 for (j = 0; j < WMNAF_PRECOMPUTED_LENGTH; ++j)
100 if ((err = ecc_projective_negate_point (pos[j], neg[j], modulus)) != 0)
101 goto done;
104 /* calculate wMNAF */
105 wmnaf = ecc_wMNAF (k, &wmnaf_len);
106 if (!wmnaf)
108 err = GNUTLS_E_INTERNAL_ERROR;
109 goto done;
112 /* actual point computation */
114 /* set R to neutral */
115 mpz_set_ui (R->x, 1);
116 mpz_set_ui (R->y, 1);
117 mpz_set_ui (R->z, 0);
119 /* perform ops */
120 for (j = wmnaf_len - 1; j >= 0; --j)
122 if ((err = ecc_projective_dbl_point (R, R, a, modulus)) != 0)
123 goto done;
125 digit = wmnaf[j];
127 if (digit)
129 if (digit > 0)
131 if ((err =
132 ecc_projective_add_point (R, pos[(digit / 2)], R, a,
133 modulus)) != 0)
134 goto done;
136 else
138 if ((err =
139 ecc_projective_add_point (R, neg[(-digit / 2)], R, a,
140 modulus)) != 0)
141 goto done;
147 /* map R back from projective space */
148 if (map)
150 err = ecc_map (R, modulus);
152 else
154 err = GNUTLS_E_SUCCESS;
156 done:
157 for (i = 0; i < WMNAF_PRECOMPUTED_LENGTH; ++i)
159 ecc_del_point (pos[i]);
160 ecc_del_point (neg[i]);
162 if (wmnaf)
163 free (wmnaf);
164 return err;