1 /******************************************************************************
2  *
3  *  Copyright (C) 2006-2015 Broadcom Corporation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 /******************************************************************************
20  *
21  *  This file contains simple pairing algorithms using Elliptic Curve Cryptography for private public key
22  *
23  ******************************************************************************/
24 //#include <stdio.h>
25 //#include <stdlib.h>
26 #include <string.h>
27 #include "p_256_ecc_pp.h"
28 #include "p_256_multprecision.h"
29 #include "common/bt_target.h"
30 
31 #if SMP_DYNAMIC_MEMORY == FALSE
32 elliptic_curve_t curve;
33 elliptic_curve_t curve_p256;
34 #else
35 elliptic_curve_t *curve_ptr;
36 elliptic_curve_t *curve_p256_ptr;
37 #endif
38 
p_256_init_point(Point * q)39 static void p_256_init_point(Point *q)
40 {
41     memset(q, 0, sizeof(Point));
42 }
43 
p_256_copy_point(Point * q,Point * p)44 static void p_256_copy_point(Point *q, Point *p)
45 {
46     memcpy(q, p, sizeof(Point));
47 }
48 
49 // q=2q
ECC_Double(Point * q,Point * p,uint32_t keyLength)50 static void ECC_Double(Point *q, Point *p, uint32_t keyLength)
51 {
52     DWORD t1[KEY_LENGTH_DWORDS_P256];
53     DWORD t2[KEY_LENGTH_DWORDS_P256];
54     DWORD t3[KEY_LENGTH_DWORDS_P256];
55     DWORD *x1;
56     DWORD *x3;
57     DWORD *y1;
58     DWORD *y3;
59     DWORD *z1;
60     DWORD *z3;
61 
62     if (multiprecision_iszero(p->z, keyLength)) {
63         multiprecision_init(q->z, keyLength);
64         return;                                     // return infinity
65     }
66 
67     x1 = p->x; y1 = p->y; z1 = p->z;
68     x3 = q->x; y3 = q->y; z3 = q->z;
69 
70     multiprecision_mersenns_squa_mod(t1, z1, keyLength);  // t1=z1^2
71     multiprecision_sub_mod(t2, x1, t1, keyLength);  // t2=x1-t1
72     multiprecision_add_mod(t1, x1, t1, keyLength);  // t1=x1+t1
73     multiprecision_mersenns_mult_mod(t2, t1, t2, keyLength);  // t2=t2*t1
74     multiprecision_lshift_mod(t3, t2, keyLength);
75     multiprecision_add_mod(t2, t3, t2, keyLength);  // t2=3t2
76 
77     multiprecision_mersenns_mult_mod(z3, y1, z1, keyLength);  // z3=y1*z1
78     multiprecision_lshift_mod(z3, z3, keyLength);
79 
80     multiprecision_mersenns_squa_mod(y3, y1, keyLength);  // y3=y1^2
81     multiprecision_lshift_mod(y3, y3, keyLength);
82     multiprecision_mersenns_mult_mod(t3, y3, x1, keyLength);  // t3=y3*x1=x1*y1^2
83     multiprecision_lshift_mod(t3, t3, keyLength);
84     multiprecision_mersenns_squa_mod(y3, y3, keyLength);  // y3=y3^2=y1^4
85     multiprecision_lshift_mod(y3, y3, keyLength);
86 
87     multiprecision_mersenns_squa_mod(x3, t2, keyLength);  // x3=t2^2
88     multiprecision_lshift_mod(t1, t3, keyLength);                // t1=2t3
89     multiprecision_sub_mod(x3, x3, t1, keyLength);               // x3=x3-t1
90     multiprecision_sub_mod(t1, t3, x3, keyLength);               // t1=t3-x3
91     multiprecision_mersenns_mult_mod(t1, t1, t2, keyLength);  // t1=t1*t2
92     multiprecision_sub_mod(y3, t1, y3, keyLength);               // y3=t1-y3
93 }
94 
95 // q=q+p,     zp must be 1
ECC_Add(Point * r,Point * p,Point * q,uint32_t keyLength)96 static void ECC_Add(Point *r, Point *p, Point *q, uint32_t keyLength)
97 {
98     DWORD t1[KEY_LENGTH_DWORDS_P256];
99     DWORD t2[KEY_LENGTH_DWORDS_P256];
100     DWORD *x1;
101     DWORD *x2;
102     DWORD *x3;
103     DWORD *y1;
104     DWORD *y2;
105     DWORD *y3;
106     DWORD *z1;
107     DWORD *z2;
108     DWORD *z3;
109 
110     x1 = p->x; y1 = p->y; z1 = p->z;
111     x2 = q->x; y2 = q->y; z2 = q->z;
112     x3 = r->x; y3 = r->y; z3 = r->z;
113 
114     // if Q=infinity, return p
115     if (multiprecision_iszero(z2, keyLength)) {
116         p_256_copy_point(r, p);
117         return;
118     }
119 
120     // if P=infinity, return q
121     if (multiprecision_iszero(z1, keyLength)) {
122         p_256_copy_point(r, q);
123         return;
124     }
125 
126     multiprecision_mersenns_squa_mod(t1, z1, keyLength);      // t1=z1^2
127     multiprecision_mersenns_mult_mod(t2, z1, t1, keyLength);  // t2=t1*z1
128     multiprecision_mersenns_mult_mod(t1, x2, t1, keyLength);  // t1=t1*x2
129     multiprecision_mersenns_mult_mod(t2, y2, t2, keyLength);  // t2=t2*y2
130 
131     multiprecision_sub_mod(t1, t1, x1, keyLength);  // t1=t1-x1
132     multiprecision_sub_mod(t2, t2, y1, keyLength);  // t2=t2-y1
133 
134     if (multiprecision_iszero(t1, keyLength)) {
135         if (multiprecision_iszero(t2, keyLength)) {
136             ECC_Double(r, q, keyLength) ;
137             return;
138         } else {
139             multiprecision_init(z3, keyLength);
140             return;                             // return infinity
141         }
142     }
143 
144     multiprecision_mersenns_mult_mod(z3, z1, t1, keyLength);  // z3=z1*t1
145     multiprecision_mersenns_squa_mod(y3, t1, keyLength);      // t3=t1^2
146     multiprecision_mersenns_mult_mod(z1, y3, t1, keyLength);  // t4=t3*t1
147     multiprecision_mersenns_mult_mod(y3, y3, x1, keyLength);  // t3=t3*x1
148     multiprecision_lshift_mod(t1, y3, keyLength);            // t1=2*t3
149     multiprecision_mersenns_squa_mod(x3, t2, keyLength);      // x3=t2^2
150     multiprecision_sub_mod(x3, x3, t1, keyLength);           // x3=x3-t1
151     multiprecision_sub_mod(x3, x3, z1, keyLength);           // x3=x3-t4
152     multiprecision_sub_mod(y3, y3, x3, keyLength);           // t3=t3-x3
153     multiprecision_mersenns_mult_mod(y3, y3, t2, keyLength);  // t3=t3*t2
154     multiprecision_mersenns_mult_mod(z1, z1, y1, keyLength);  // t4=t4*t1
155     multiprecision_sub_mod(y3, y3, z1, keyLength);
156 }
157 
158 // Computing the Non-Adjacent Form of a positive integer
ECC_NAF(uint8_t * naf,uint32_t * NumNAF,DWORD * k,uint32_t keyLength)159 static void ECC_NAF(uint8_t *naf, uint32_t *NumNAF, DWORD *k, uint32_t keyLength)
160 {
161     uint32_t sign;
162     int i = 0;
163     int j;
164     uint32_t var;
165 
166     while ((var = multiprecision_most_signbits(k, keyLength)) >= 1) {
167         if (k[0] & 0x01) { // k is odd
168             sign = (k[0] & 0x03);  // 1 or 3
169 
170             // k = k-naf[i]
171             if (sign == 1) {
172                 k[0] = k[0] & 0xFFFFFFFE;
173             } else {
174                 k[0] = k[0] + 1;
175                 if (k[0] == 0) { //overflow
176                     j = 1;
177                     do {
178                         k[j]++;
179                     } while (k[j++] == 0); //overflow
180                 }
181             }
182         } else {
183             sign = 0;
184         }
185 
186         multiprecision_rshift(k, k, keyLength);
187         naf[i / 4] |= (sign) << ((i % 4) * 2);
188         i++;
189     }
190 
191     *NumNAF = i;
192 }
193 
194 // Binary Non-Adjacent Form for point multiplication
ECC_PointMult_Bin_NAF(Point * q,Point * p,DWORD * n,uint32_t keyLength)195 void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength)
196 {
197     uint32_t sign;
198     UINT8 naf[256 / 4 + 1];
199     uint32_t NumNaf;
200     Point minus_p;
201     Point r;
202     DWORD *modp;
203 
204     if (keyLength == KEY_LENGTH_DWORDS_P256) {
205         modp = curve_p256.p;
206     } else {
207         modp = curve.p;
208     }
209 
210     p_256_init_point(&r);
211     multiprecision_init(p->z, keyLength);
212     p->z[0] = 1;
213 
214     // initialization
215     p_256_init_point(q);
216 
217     // -p
218     multiprecision_copy(minus_p.x, p->x, keyLength);
219     multiprecision_sub(minus_p.y, modp, p->y, keyLength);
220 
221     multiprecision_init(minus_p.z, keyLength);
222     minus_p.z[0] = 1;
223 
224     // NAF
225     memset(naf, 0, sizeof(naf));
226     ECC_NAF(naf, &NumNaf, n, keyLength);
227 
228     for (int i = NumNaf - 1; i >= 0; i--) {
229         p_256_copy_point(&r, q);
230         ECC_Double(q, &r, keyLength);
231         sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
232 
233         if (sign == 1) {
234             p_256_copy_point(&r, q);
235             ECC_Add(q, &r, p, keyLength);
236         } else if (sign == 3) {
237             p_256_copy_point(&r, q);
238             ECC_Add(q, &r, &minus_p, keyLength);
239         }
240     }
241 
242     multiprecision_inv_mod(minus_p.x, q->z, keyLength);
243     multiprecision_mersenns_squa_mod(q->z, minus_p.x, keyLength);
244     multiprecision_mersenns_mult_mod(q->x, q->x, q->z, keyLength);
245     multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength);
246     multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
247 }
248 
ECC_CheckPointIsInElliCur_P256(Point * p)249 bool ECC_CheckPointIsInElliCur_P256(Point *p)
250 {
251     /* y^2 % q */
252     DWORD y_y_q[KEY_LENGTH_DWORDS_P256] = {0x0};
253     /* x^2 % q */
254     DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
255     /* x % q */
256     DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
257     /* x^2, To prevent overflow, the length of the x square here needs to
258        be expanded to two times the original one. */
259     DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0};
260     /* y_y_q =(p->y)^2(mod q) */
261     multiprecision_mersenns_squa_mod(y_y_q, p->y, KEY_LENGTH_DWORDS_P256);
262     /* Calculate the value of p->x square, x_x = (p->x)^2 */
263     multiprecision_mult(x_x, p->x, p->x, KEY_LENGTH_DWORDS_P256);
264     /* The function of the elliptic curve is y^2 = x^3 - 3x + b (mod q) ==>
265        y^2 = (x^2 - 3)*x + b (mod q),
266        so we calculate the x^2 - 3 value here */
267     x_x[0] -= 3;
268     /* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==>
269       (x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */
270     multiprecision_fast_mod_P256(x_x_q, x_x);
271     /* x_x = x_x_q * x_q */
272     multiprecision_mult(x_x, x_x_q, p->x, KEY_LENGTH_DWORDS_P256);
273     /* x_q = x_x % q */
274     multiprecision_fast_mod_P256(x_q, x_x);
275     /* Save the result in x_x_q */
276     multiprecision_add_mod(x_x_q, x_q, curve_p256.b, KEY_LENGTH_DWORDS_P256);
277     /* compare the y_y_q and x_x_q, see if they are on a given elliptic curve. */
278     if (multiprecision_compare(y_y_q, x_x_q, KEY_LENGTH_DWORDS_P256)) {
279         return false;
280     } else {
281         return true;
282     }
283 }
284