1 /******************************************************************************
2 * Filename: pka.c
3 * Revised: 2020-09-14 11:11:23 +0200 (Mon, 14 Sep 2020)
4 * Revision: 58613
5 *
6 * Description: Driver for the PKA module
7 *
8 * Copyright (c) 2015 - 2020, Texas Instruments Incorporated
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * 1) Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 *
17 * 2) Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 *
21 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
22 * be used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ******************************************************************************/
38
39 #include "pka.h"
40
41 //*****************************************************************************
42 //
43 // Handle support for DriverLib in ROM:
44 // This section will undo prototype renaming made in the header file
45 //
46 //*****************************************************************************
47 #if !defined(DOXYGEN)
48 #undef PKAClearPkaRam
49 #define PKAClearPkaRam NOROM_PKAClearPkaRam
50 #undef PKAGetOpsStatus
51 #define PKAGetOpsStatus NOROM_PKAGetOpsStatus
52 #undef PKAArrayAllZeros
53 #define PKAArrayAllZeros NOROM_PKAArrayAllZeros
54 #undef PKAZeroOutArray
55 #define PKAZeroOutArray NOROM_PKAZeroOutArray
56 #undef PKABigNumModStart
57 #define PKABigNumModStart NOROM_PKABigNumModStart
58 #undef PKABigNumModGetResult
59 #define PKABigNumModGetResult NOROM_PKABigNumModGetResult
60 #undef PKABigNumDivideStart
61 #define PKABigNumDivideStart NOROM_PKABigNumDivideStart
62 #undef PKABigNumDivideGetQuotient
63 #define PKABigNumDivideGetQuotient NOROM_PKABigNumDivideGetQuotient
64 #undef PKABigNumDivideGetRemainder
65 #define PKABigNumDivideGetRemainder NOROM_PKABigNumDivideGetRemainder
66 #undef PKABigNumCmpStart
67 #define PKABigNumCmpStart NOROM_PKABigNumCmpStart
68 #undef PKABigNumCmpGetResult
69 #define PKABigNumCmpGetResult NOROM_PKABigNumCmpGetResult
70 #undef PKABigNumInvModStart
71 #define PKABigNumInvModStart NOROM_PKABigNumInvModStart
72 #undef PKABigNumInvModGetResult
73 #define PKABigNumInvModGetResult NOROM_PKABigNumInvModGetResult
74 #undef PKABigNumMultiplyStart
75 #define PKABigNumMultiplyStart NOROM_PKABigNumMultiplyStart
76 #undef PKABigNumMultGetResult
77 #define PKABigNumMultGetResult NOROM_PKABigNumMultGetResult
78 #undef PKABigNumAddStart
79 #define PKABigNumAddStart NOROM_PKABigNumAddStart
80 #undef PKABigNumAddGetResult
81 #define PKABigNumAddGetResult NOROM_PKABigNumAddGetResult
82 #undef PKABigNumSubStart
83 #define PKABigNumSubStart NOROM_PKABigNumSubStart
84 #undef PKABigNumSubGetResult
85 #define PKABigNumSubGetResult NOROM_PKABigNumSubGetResult
86 #undef PKAEccMultiplyStart
87 #define PKAEccMultiplyStart NOROM_PKAEccMultiplyStart
88 #undef PKAEccMontgomeryMultiplyStart
89 #define PKAEccMontgomeryMultiplyStart NOROM_PKAEccMontgomeryMultiplyStart
90 #undef PKAEccMultiplyGetResult
91 #define PKAEccMultiplyGetResult NOROM_PKAEccMultiplyGetResult
92 #undef PKAEccAddStart
93 #define PKAEccAddStart NOROM_PKAEccAddStart
94 #undef PKAEccAddGetResult
95 #define PKAEccAddGetResult NOROM_PKAEccAddGetResult
96 #undef PKAEccVerifyPublicKeyWeierstrassStart
97 #define PKAEccVerifyPublicKeyWeierstrassStart NOROM_PKAEccVerifyPublicKeyWeierstrassStart
98 #endif
99
100
101
102 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
103 #define MIN(x,y) (((x) < (y)) ? (x) : (y))
104 #define INRANGE(x,y,z) ((x) > (y) && (x) < (z))
105
106
107 //*****************************************************************************
108 //
109 // Define for the maximum curve size supported by the PKA module in 32 bit
110 // word.
111 // \note PKA hardware module can support up to 384 bit curve size due to the
112 // 2K of PKA RAM.
113 //
114 //*****************************************************************************
115 #define PKA_MAX_CURVE_SIZE_32_BIT_WORD 12
116
117 //*****************************************************************************
118 //
119 // Define for the maximum length of the big number supported by the PKA module
120 // in 32 bit word.
121 //
122 //*****************************************************************************
123 #define PKA_MAX_LEN_IN_32_BIT_WORD PKA_MAX_CURVE_SIZE_32_BIT_WORD
124
125 //*****************************************************************************
126 //
127 // Used in PKAWritePkaParam() and PKAWritePkaParamExtraOffset() to specify that
128 // the base address of the parameter should not be written to a NPTR register.
129 //
130 //*****************************************************************************
131 #define PKA_NO_POINTER_REG 0xFF
132
133 //*****************************************************************************
134 //
135 // NIST P224 constants in little endian format. byte[0] is the least
136 // significant byte and byte[NISTP224_PARAM_SIZE_BYTES - 1] is the most
137 // significant.
138 //
139 //*****************************************************************************
140 const PKA_EccPoint224 NISTP224_generator = {
141 .x = {.byte = {0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34,
142 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A,
143 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B,
144 0xBD, 0x0C, 0x0E, 0xB7, }},
145 .y = {.byte = {0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44,
146 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD,
147 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5,
148 0x88, 0x63, 0x37, 0xBD, }},
149 };
150
151 const PKA_EccParam224 NISTP224_prime = {.byte = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
153 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
154 0xFF, 0xFF, 0xFF, 0xFF}};
155
156 const PKA_EccParam224 NISTP224_a = {.byte = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
157 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
158 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
159 0xFF, 0xFF, 0xFF, 0xFF}};
160
161 const PKA_EccParam224 NISTP224_b = {.byte = {0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27,
162 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50,
163 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C,
164 0x85, 0x0A, 0x05, 0xB4}};
165
166 const PKA_EccParam224 NISTP224_order = {.byte = {0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13,
167 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF,
168 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
169 0xFF, 0xFF, 0xFF, 0xFF}};
170
171 //*****************************************************************************
172 //
173 // NIST P256 constants in little endian format. byte[0] is the least
174 // significant byte and byte[NISTP256_PARAM_SIZE_BYTES - 1] is the most
175 // significant.
176 //
177 //*****************************************************************************
178 const PKA_EccPoint256 NISTP256_generator = {
179 .x = {.byte = {0x96, 0xc2, 0x98, 0xd8, 0x45, 0x39, 0xa1, 0xf4,
180 0xa0, 0x33, 0xeb, 0x2d, 0x81, 0x7d, 0x03, 0x77,
181 0xf2, 0x40, 0xa4, 0x63, 0xe5, 0xe6, 0xbc, 0xf8,
182 0x47, 0x42, 0x2c, 0xe1, 0xf2, 0xd1, 0x17, 0x6b}},
183 .y = {.byte = {0xf5, 0x51, 0xbf, 0x37, 0x68, 0x40, 0xb6, 0xcb,
184 0xce, 0x5e, 0x31, 0x6b, 0x57, 0x33, 0xce, 0x2b,
185 0x16, 0x9e, 0x0f, 0x7c, 0x4a, 0xeb, 0xe7, 0x8e,
186 0x9b, 0x7f, 0x1a, 0xfe, 0xe2, 0x42, 0xe3, 0x4f}},
187 };
188
189 const PKA_EccParam256 NISTP256_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
190 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
193
194 const PKA_EccParam256 NISTP256_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
195 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
198
199 const PKA_EccParam256 NISTP256_b = {.byte = {0x4b, 0x60, 0xd2, 0x27, 0x3e, 0x3c, 0xce, 0x3b,
200 0xf6, 0xb0, 0x53, 0xcc, 0xb0, 0x06, 0x1d, 0x65,
201 0xbc, 0x86, 0x98, 0x76, 0x55, 0xbd, 0xeb, 0xb3,
202 0xe7, 0x93, 0x3a, 0xaa, 0xd8, 0x35, 0xc6, 0x5a}};
203
204 const PKA_EccParam256 NISTP256_order = {.byte = {0x51, 0x25, 0x63, 0xfc, 0xc2, 0xca, 0xb9, 0xf3,
205 0x84, 0x9e, 0x17, 0xa7, 0xad, 0xfa, 0xe6, 0xbc,
206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
207 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
208
209 //*****************************************************************************
210 //
211 // NIST P384 constants in little endian format. byte[0] is the least
212 // significant byte and byte[NISTP384_PARAM_SIZE_BYTES - 1] is the most
213 // significant.
214 //
215 //*****************************************************************************
216 const PKA_EccPoint384 NISTP384_generator = {
217 .x = {.byte = {0xb7, 0x0a, 0x76, 0x72, 0x38, 0x5e, 0x54, 0x3a,
218 0x6c, 0x29, 0x55, 0xbf, 0x5d, 0xf2, 0x02, 0x55,
219 0x38, 0x2a, 0x54, 0x82, 0xe0, 0x41, 0xf7, 0x59,
220 0x98, 0x9b, 0xa7, 0x8b, 0x62, 0x3b, 0x1d, 0x6e,
221 0x74, 0xad, 0x20, 0xf3, 0x1e, 0xc7, 0xb1, 0x8e,
222 0x37, 0x05, 0x8b, 0xbe, 0x22, 0xca, 0x87, 0xaa}},
223 .y = {.byte = {0x5f, 0x0e, 0xea, 0x90, 0x7c, 0x1d, 0x43, 0x7a,
224 0x9d, 0x81, 0x7e, 0x1d, 0xce, 0xb1, 0x60, 0x0a,
225 0xc0, 0xb8, 0xf0, 0xb5, 0x13, 0x31, 0xda, 0xe9,
226 0x7c, 0x14, 0x9a, 0x28, 0xbd, 0x1d, 0xf4, 0xf8,
227 0x29, 0xdc, 0x92, 0x92, 0xbf, 0x98, 0x9e, 0x5d,
228 0x6f, 0x2c, 0x26, 0x96, 0x4a, 0xde, 0x17, 0x36,}},
229 };
230
231 const PKA_EccParam384 NISTP384_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
233 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
234 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
235 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
236 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
237
238 const PKA_EccParam384 NISTP384_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
240 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
241 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
242 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
243 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
244
245 const PKA_EccParam384 NISTP384_b = {.byte = {0xef, 0x2a, 0xec, 0xd3, 0xed, 0xc8, 0x85, 0x2a,
246 0x9d, 0xd1, 0x2e, 0x8a, 0x8d, 0x39, 0x56, 0xc6,
247 0x5a, 0x87, 0x13, 0x50, 0x8f, 0x08, 0x14, 0x03,
248 0x12, 0x41, 0x81, 0xfe, 0x6e, 0x9c, 0x1d, 0x18,
249 0x19, 0x2d, 0xf8, 0xe3, 0x6b, 0x05, 0x8e, 0x98,
250 0xe4, 0xe7, 0x3e, 0xe2, 0xa7, 0x2f, 0x31, 0xb3}};
251
252 const PKA_EccParam384 NISTP384_order = {.byte = {0x73, 0x29, 0xc5, 0xcc, 0x6a, 0x19, 0xec, 0xec,
253 0x7a, 0xa7, 0xb0, 0x48, 0xb2, 0x0d, 0x1a, 0x58,
254 0xdf, 0x2d, 0x37, 0xf4, 0x81, 0x4d, 0x63, 0xc7,
255 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
256 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
257 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
258
259
260 //*****************************************************************************
261 //
262 // NIST P521 constants in little endian format. byte[0] is the least
263 // significant byte and byte[NISTP521_PARAM_SIZE_BYTES - 1] is the most
264 // significant.
265 //
266 //*****************************************************************************
267 const PKA_EccPoint521 NISTP521_generator = {
268 .x = {.byte = {0x66, 0xbd, 0xe5, 0xc2, 0x31, 0x7e, 0x7e, 0xf9,
269 0x9b, 0x42, 0x6a, 0x85, 0xc1, 0xb3, 0x48, 0x33,
270 0xde, 0xa8, 0xff, 0xa2, 0x27, 0xc1, 0x1d, 0xfe,
271 0x28, 0x59, 0xe7, 0xef, 0x77, 0x5e, 0x4b, 0xa1,
272 0xba, 0x3d, 0x4d, 0x6b, 0x60, 0xaf, 0x28, 0xf8,
273 0x21, 0xb5, 0x3f, 0x05, 0x39, 0x81, 0x64, 0x9c,
274 0x42, 0xb4, 0x95, 0x23, 0x66, 0xcb, 0x3e, 0x9e,
275 0xcd, 0xe9, 0x04, 0x04, 0xb7, 0x06, 0x8e, 0x85,
276 0xc6, 0x00}},
277 .y = {.byte = {0x50, 0x66, 0xd1, 0x9f, 0x76, 0x94, 0xbe, 0x88,
278 0x40, 0xc2, 0x72, 0xa2, 0x86, 0x70, 0x3c, 0x35,
279 0x61, 0x07, 0xad, 0x3f, 0x01, 0xb9, 0x50, 0xc5,
280 0x40, 0x26, 0xf4, 0x5e, 0x99, 0x72, 0xee, 0x97,
281 0x2c, 0x66, 0x3e, 0x27, 0x17, 0xbd, 0xaf, 0x17,
282 0x68, 0x44, 0x9b, 0x57, 0x49, 0x44, 0xf5, 0x98,
283 0xd9, 0x1b, 0x7d, 0x2c, 0xb4, 0x5f, 0x8a, 0x5c,
284 0x04, 0xc0, 0x3b, 0x9a, 0x78, 0x6a, 0x29, 0x39,
285 0x18, 0x01}},
286 };
287
288 const PKA_EccParam521 NISTP521_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
289 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
290 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
291 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
292 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
293 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
294 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
295 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
296 0xff, 0x01}};
297
298 const PKA_EccParam521 NISTP521_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
299 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
300 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
301 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
302 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
303 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
304 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
305 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
306 0xff, 0x01}};
307
308 const PKA_EccParam521 NISTP521_b = {.byte = {0x00, 0x3f, 0x50, 0x6b, 0xd4, 0x1f, 0x45, 0xef,
309 0xf1, 0x34, 0x2c, 0x3d, 0x88, 0xdf, 0x73, 0x35,
310 0x07, 0xbf, 0xb1, 0x3b, 0xbd, 0xc0, 0x52, 0x16,
311 0x7b, 0x93, 0x7e, 0xec, 0x51, 0x39, 0x19, 0x56,
312 0xe1, 0x09, 0xf1, 0x8e, 0x91, 0x89, 0xb4, 0xb8,
313 0xf3, 0x15, 0xb3, 0x99, 0x5b, 0x72, 0xda, 0xa2,
314 0xee, 0x40, 0x85, 0xb6, 0xa0, 0x21, 0x9a, 0x92,
315 0x1f, 0x9a, 0x1c, 0x8e, 0x61, 0xb9, 0x3e, 0x95,
316 0x51, 0x00}};
317
318 const PKA_EccParam521 NISTP521_order = {.byte = {0x09, 0x64, 0x38, 0x91, 0x1e, 0xb7, 0x6f, 0xbb,
319 0xae, 0x47, 0x9c, 0x89, 0xb8, 0xc9, 0xb5, 0x3b,
320 0xd0, 0xa5, 0x09, 0xf7, 0x48, 0x01, 0xcc, 0x7f,
321 0x6b, 0x96, 0x2f, 0xbf, 0x83, 0x87, 0x86, 0x51,
322 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
323 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
324 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
325 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
326 0xff, 0x01}};
327
328
329 //*****************************************************************************
330 //
331 // Brainpool P256r1 constants in little endian format. byte[0] is the least
332 // significant byte and byte[BrainpoolP256R1_PARAM_SIZE_BYTES - 1] is the most
333 // significant.
334 //
335 //*****************************************************************************
336 const PKA_EccPoint256 BrainpoolP256R1_generator = {
337 .x = {.byte = {0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A,
338 0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9,
339 0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C,
340 0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B}},
341 .y = {.byte = {0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C,
342 0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2,
343 0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97,
344 0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54}},
345 };
346
347 const PKA_EccParam256 BrainpoolP256R1_prime = {.byte = {0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20,
348 0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E,
349 0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E,
350 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9}};
351
352 const PKA_EccParam256 BrainpoolP256R1_a = {.byte = {0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9,
353 0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB,
354 0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE,
355 0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D}};
356
357 const PKA_EccParam256 BrainpoolP256R1_b = {.byte = {0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B,
358 0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95,
359 0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3,
360 0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26,}};
361
362 const PKA_EccParam256 BrainpoolP256R1_order = {.byte = {0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90,
363 0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C,
364 0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E,
365 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9}};
366
367 //*****************************************************************************
368 //
369 // Brainpool P384r1 constants in little endian format. byte[0] is the least
370 // significant byte and byte[BrainpoolP384R1_PARAM_SIZE_BYTES - 1] is the most
371 // significant.
372 //
373 //*****************************************************************************
374 const PKA_EccPoint384 BrainpoolP384R1_generator = {
375 .x = {.byte = {0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF,
376 0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8,
377 0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB,
378 0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88,
379 0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2,
380 0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D}},
381 .y = {.byte = {0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42,
382 0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E,
383 0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1,
384 0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62,
385 0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C,
386 0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A}},
387 };
388
389 const PKA_EccParam384 BrainpoolP384R1_prime = {.byte = {0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87,
390 0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC,
391 0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12,
392 0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15,
393 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F,
394 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C}};
395
396 const PKA_EccParam384 BrainpoolP384R1_a = {.byte = {0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04,
397 0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A,
398 0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13,
399 0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2,
400 0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C,
401 0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B}};
402
403 const PKA_EccParam384 BrainpoolP384R1_b = {.byte = {0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A,
404 0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C,
405 0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E,
406 0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F,
407 0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B,
408 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04}};
409
410 const PKA_EccParam384 BrainpoolP384R1_order = {.byte = {0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B,
411 0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF,
412 0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F,
413 0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15,
414 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F,
415 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C}};
416
417 //*****************************************************************************
418 //
419 // Brainpool P512r1 constants in little endian format. byte[0] is the least
420 // significant byte and byte[BrainpoolP512R1_PARAM_SIZE_BYTES - 1] is the most
421 // significant.
422 //
423 //*****************************************************************************
424 const PKA_EccPoint512 BrainpoolP512R1_generator = {
425 .x = {.byte = {0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B,
426 0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C,
427 0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50,
428 0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF,
429 0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4,
430 0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85,
431 0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A,
432 0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81}},
433 .y = {.byte = {0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78,
434 0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1,
435 0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B,
436 0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2,
437 0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0,
438 0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2,
439 0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0,
440 0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D}},
441 };
442
443 const PKA_EccParam512 BrainpoolP512R1_prime = {.byte = {0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28,
444 0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28,
445 0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE,
446 0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D,
447 0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6,
448 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB,
449 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F,
450 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA}};
451
452 const PKA_EccParam512 BrainpoolP512R1_a = {.byte = {0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7,
453 0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F,
454 0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A,
455 0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D,
456 0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8,
457 0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94,
458 0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2,
459 0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78}};
460
461 const PKA_EccParam512 BrainpoolP512R1_b = {.byte = {0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28,
462 0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98,
463 0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77,
464 0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B,
465 0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B,
466 0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8,
467 0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA,
468 0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D}};
469
470 const PKA_EccParam512 BrainpoolP512R1_order = {.byte = {0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5,
471 0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D,
472 0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41,
473 0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55,
474 0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6,
475 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB,
476 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F,
477 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA}};
478
479 //*****************************************************************************
480 //
481 // Curve25519 constants in little endian format. byte[0] is the least
482 // significant byte and byte[Curve25519_PARAM_SIZE_BYTES - 1] is the most
483 // significant.
484 //
485 //*****************************************************************************
486 const PKA_EccPoint256 Curve25519_generator = {
487 .x = {.byte = {0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}},
491 .y = {.byte = {0xd9, 0xd3, 0xce, 0x7e, 0xa2, 0xc5, 0xe9, 0x29,
492 0xb2, 0x61, 0x7c, 0x6d, 0x7e, 0x4d, 0x3d, 0x92,
493 0x4c, 0xd1, 0x48, 0x77, 0x2c, 0xdd, 0x1e, 0xe0,
494 0xb4, 0x86, 0xa0, 0xb8, 0xa1, 0x19, 0xae, 0x20}},
495 };
496
497 const PKA_EccParam256 Curve25519_prime = {.byte = {0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
498 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
499 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
500 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}};
501
502 const PKA_EccParam256 Curve25519_a = {.byte = {0x06, 0x6d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
506
507 const PKA_EccParam256 Curve25519_b = {.byte = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
511
512 const PKA_EccParam256 Curve25519_order = {.byte = {0xb9, 0xdc, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
513 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
516
517
518 //*****************************************************************************
519 //
520 // Zeroize PKA RAM. Not threadsafe.
521 //
522 //*****************************************************************************
PKAClearPkaRam(void)523 void PKAClearPkaRam(void){
524 // Get initial state
525 uint32_t secdmaclkgr = HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR);
526
527 // OR in zeroize bit
528 secdmaclkgr |= PRCM_SECDMACLKGR_PKA_ZERIOZE_RESET_N;
529
530 // Start zeroization
531 HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) = secdmaclkgr;
532
533 // Wait 256 cycles for PKA RAM to be cleared
534 CPUdelay(256 / 4);
535
536 // Turn off zeroization
537 HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) = secdmaclkgr & (~PRCM_SECDMACLKGR_PKA_ZERIOZE_RESET_N);
538 }
539
540 //*****************************************************************************
541 //
542 // Write a PKA parameter to the PKA module, set required registers, and add an offset.
543 //
544 //*****************************************************************************
PKAWritePkaParam(const uint8_t * param,uint32_t paramLength,uint32_t paramOffset,uint32_t ptrRegOffset)545 static uint32_t PKAWritePkaParam(const uint8_t *param, uint32_t paramLength, uint32_t paramOffset, uint32_t ptrRegOffset)
546 {
547 uint32_t i;
548 uint32_t *paramWordAlias = (uint32_t *)param;
549 // Take the floor of paramLength in 32-bit words
550 uint32_t paramLengthInWords = paramLength / sizeof(uint32_t);
551
552 // Only copy data if it is specified. We may wish to simply allocate another buffer and get
553 // the required offset.
554 if (param) {
555 // Load the number in PKA RAM
556 for (i = 0; i < paramLengthInWords; i++) {
557 HWREG(PKA_RAM_BASE + paramOffset + sizeof(uint32_t) * i) = paramWordAlias[i];
558 }
559
560 // If the length is not a word-multiple, fill up a temporary word and copy that in
561 // to avoid a bus error. The extra zeros at the end should not matter, as the large
562 // number is little-endian and thus has no effect.
563 // We could have correctly calculated ceiling(paramLength / sizeof(uint32_t)) above.
564 // However, we would not have been able to zero-out the extra few most significant
565 // bytes of the most significant word. That would have resulted in doing maths operations
566 // on whatever follows param in RAM.
567 if (paramLength % sizeof(uint32_t)) {
568 uint32_t temp = 0;
569 uint8_t j;
570
571 // Load the entire word line of the param remainder
572 temp = paramWordAlias[i];
573
574 // Zero-out all bytes beyond the end of the param
575 for (j = paramLength % sizeof(uint32_t); j < sizeof(uint32_t); j++) {
576 ((uint8_t *)&temp)[j] = 0;
577 }
578
579 HWREG(PKA_RAM_BASE + paramOffset + sizeof(uint32_t) * i) = temp;
580
581 // Increment paramLengthInWords since we take the ceiling of length / sizeof(uint32_t)
582 paramLengthInWords++;
583 }
584 }
585
586 // Update the A, B, C, or D pointer with the offset address of the PKA RAM location
587 // where the number will be stored.
588 switch (ptrRegOffset) {
589 case PKA_O_APTR:
590 HWREG(PKA_BASE + PKA_O_APTR) = paramOffset >> 2;
591 HWREG(PKA_BASE + PKA_O_ALENGTH) = paramLengthInWords;
592 break;
593 case PKA_O_BPTR:
594 HWREG(PKA_BASE + PKA_O_BPTR) = paramOffset >> 2;
595 HWREG(PKA_BASE + PKA_O_BLENGTH) = paramLengthInWords;
596 break;
597 case PKA_O_CPTR:
598 HWREG(PKA_BASE + PKA_O_CPTR) = paramOffset >> 2;
599 break;
600 case PKA_O_DPTR:
601 HWREG(PKA_BASE + PKA_O_DPTR) = paramOffset >> 2;
602 break;
603 }
604
605 // Ensure 8-byte alignment of next parameter.
606 // Returns the offset for the next parameter.
607 return paramOffset + sizeof(uint32_t) * (paramLengthInWords + (paramLengthInWords % 2));
608 }
609
610 //*****************************************************************************
611 //
612 // Write a PKA parameter to the PKA module but return a larger offset.
613 //
614 //*****************************************************************************
PKAWritePkaParamExtraOffset(const uint8_t * param,uint32_t paramLength,uint32_t paramOffset,uint32_t ptrRegOffset)615 static uint32_t PKAWritePkaParamExtraOffset(const uint8_t *param, uint32_t paramLength, uint32_t paramOffset, uint32_t ptrRegOffset)
616 {
617 // Ensure 16-byte alignment.
618 return (sizeof(uint32_t) * 2) + PKAWritePkaParam(param, paramLength, paramOffset, ptrRegOffset);
619 }
620
621 //*****************************************************************************
622 //
623 // Writes the result of a large number arithmetic operation to a provided buffer.
624 //
625 //*****************************************************************************
PKAGetBigNumResult(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)626 static uint32_t PKAGetBigNumResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
627 {
628 uint32_t mswOffset;
629 uint32_t lswOffset;
630 uint32_t lengthInWords;
631 uint32_t i;
632 uint32_t *resultWordAlias = (uint32_t *)resultBuf;
633
634 // Check the arguments.
635 ASSERT(resultBuf);
636 ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
637 (resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
638
639 // Verify that the operation is complete.
640 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
641 return PKA_STATUS_OPERATION_BUSY;
642 }
643
644 // Get the MSW register value.
645 mswOffset = HWREG(PKA_BASE + PKA_O_MSW);
646
647 // If the result vector is zero, write back one zero byte so the caller does not need
648 // to handle a special error for the perhaps valid result of zero.
649 // They will only get the error status if they do not provide a buffer
650 if (mswOffset & PKA_MSW_RESULT_IS_ZERO_M) {
651 if (*resultLength){
652 if(resultBuf){
653 resultBuf[0] = 0;
654 }
655
656 *resultLength = 1;
657
658 return PKA_STATUS_SUCCESS;
659 }
660 else {
661 return PKA_STATUS_BUF_UNDERFLOW;
662 }
663 }
664
665 // Get the length of the result
666 mswOffset = ((mswOffset & PKA_MSW_MSW_ADDRESS_M) + 1);
667 lswOffset = ((resultPKAMemAddr - PKA_RAM_BASE) >> 2);
668
669 if (mswOffset >= lswOffset) {
670 lengthInWords = mswOffset - lswOffset;
671 }
672 else {
673 return PKA_STATUS_RESULT_ADDRESS_INCORRECT;
674 }
675
676 // Check if the provided buffer length is adequate to store the result data.
677 if (*resultLength < lengthInWords * sizeof(uint32_t)) {
678 return PKA_STATUS_BUF_UNDERFLOW;
679 }
680
681 // Copy the resultant length.
682 *resultLength = lengthInWords * sizeof(uint32_t);
683
684
685 if (resultBuf) {
686 // Copy the result into the resultBuf.
687 for (i = 0; i < lengthInWords; i++) {
688 resultWordAlias[i]= HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
689 }
690 }
691
692 return PKA_STATUS_SUCCESS;
693 }
694
695 //*****************************************************************************
696 //
697 // Retrieve the result of a modulo operation or the remainder of a division.
698 //
699 //*****************************************************************************
PKAGetBigNumResultRemainder(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)700 static uint32_t PKAGetBigNumResultRemainder(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
701 {
702 uint32_t regMSWVal;
703 uint32_t lengthInWords;
704 uint32_t i;
705 uint32_t *resultWordAlias = (uint32_t *)resultBuf;
706
707 // Check the arguments.
708 ASSERT(resultBuf);
709 ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
710 (resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
711
712 // Verify that the operation is complete.
713 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
714 return PKA_STATUS_OPERATION_BUSY;
715 }
716
717 // Get the MSW register value.
718 regMSWVal = HWREG(PKA_BASE + PKA_O_DIVMSW);
719
720 // If the result vector is zero, write back one zero byte so the caller does not need
721 // to handle a special error for the perhaps valid result of zero.
722 // They will only get the error status if they do not provide a buffer
723 if (regMSWVal & PKA_DIVMSW_RESULT_IS_ZERO_M) {
724 if (*resultLength){
725 if(resultBuf){
726 resultBuf[0] = 0;
727 }
728
729 *resultLength = 1;
730
731 return PKA_STATUS_SUCCESS;
732 }
733 else {
734 return PKA_STATUS_BUF_UNDERFLOW;
735 }
736 }
737
738 // Get the length of the result
739 lengthInWords = ((regMSWVal & PKA_DIVMSW_MSW_ADDRESS_M) + 1) - ((resultPKAMemAddr - PKA_RAM_BASE) >> 2);
740
741 // Check if the provided buffer length is adequate to store the result data.
742 if (*resultLength < lengthInWords * sizeof(uint32_t)) {
743 return PKA_STATUS_BUF_UNDERFLOW;
744 }
745
746 // Copy the resultant length.
747 *resultLength = lengthInWords * sizeof(uint32_t);
748
749 if (resultBuf) {
750 // Copy the result into the resultBuf.
751 for (i = 0; i < lengthInWords; i++) {
752 resultWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
753 }
754 }
755
756 return PKA_STATUS_SUCCESS;
757 }
758
759 //*****************************************************************************
760 //
761 // Writes the resultant curve point of an ECC operation to the provided buffer.
762 //
763 //*****************************************************************************
PKAGetECCResult(uint8_t * curvePointX,uint8_t * curvePointY,uint32_t resultPKAMemAddr,uint32_t length)764 static uint32_t PKAGetECCResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
765 {
766 uint32_t i = 0;
767 uint32_t *xWordAlias = (uint32_t *)curvePointX;
768 uint32_t *yWordAlias = (uint32_t *)curvePointY;
769 uint32_t lengthInWordsCeiling = 0;
770
771 // Check for the arguments.
772 ASSERT(curvePointX);
773 ASSERT(curvePointY);
774 ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
775 (resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
776
777 // Verify that the operation is completed.
778 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
779 return PKA_STATUS_OPERATION_BUSY;
780 }
781
782 if (HWREG(PKA_BASE + PKA_O_SHIFT)) {
783 return PKA_STATUS_FAILURE;
784 }
785
786 // Check to make sure that the result vector is not the point at infinity.
787 if (HWREG(PKA_BASE + PKA_O_MSW) & PKA_MSW_RESULT_IS_ZERO) {
788 return PKA_STATUS_POINT_AT_INFINITY;
789 }
790
791 if (curvePointX != NULL) {
792 // Copy the x co-ordinate value of the result from vector D into
793 // the curvePoint.
794 for (i = 0; i < (length / sizeof(uint32_t)); i++) {
795 xWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
796 }
797
798 // If the length is not a word-multiple, fill up a temporary word and copy that in
799 // to avoid a bus error.
800 if (length % sizeof(uint32_t)) {
801 uint32_t temp = 0;
802 uint8_t j;
803
804 // Load the entire word line of the coordinate remainder
805 temp = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
806
807 // Write all remaining bytes to the coordinate
808 for (j = 0; j < length % sizeof(uint32_t); j++) {
809 curvePointX[i * sizeof(uint32_t) + j] = ((uint8_t *)&temp)[j];
810 }
811
812 }
813 }
814
815 lengthInWordsCeiling = (length % sizeof(uint32_t)) ? length / sizeof(uint32_t) + 1 : length / sizeof(uint32_t);
816
817 resultPKAMemAddr += sizeof(uint32_t) * (2 + lengthInWordsCeiling + (lengthInWordsCeiling % 2));
818
819 if (curvePointY != NULL) {
820 // Copy the y co-ordinate value of the result from vector D into
821 // the curvePoint.
822 for (i = 0; i < (length / sizeof(uint32_t)); i++) {
823 yWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
824 }
825
826 // If the length is not a word-multiple, fill up a temporary word and copy that in
827 // to avoid a bus error.
828 if (length % sizeof(uint32_t)) {
829 uint32_t temp = 0;
830 uint8_t j;
831
832 // Load the entire word line of the coordinate remainder
833 temp = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
834
835 // Write all remaining bytes to the coordinate
836 for (j = 0; j < length % sizeof(uint32_t); j++) {
837 curvePointY[i * sizeof(uint32_t) + j] = ((uint8_t *)&temp)[j];
838 }
839 }
840 }
841
842
843 return PKA_STATUS_SUCCESS;
844 }
845
846
847 //*****************************************************************************
848 //
849 // Provides the PKA operation status.
850 //
851 //*****************************************************************************
PKAGetOpsStatus(void)852 uint32_t PKAGetOpsStatus(void)
853 {
854 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN_M) {
855 return PKA_STATUS_OPERATION_BUSY;
856 }
857 else {
858 return PKA_STATUS_OPERATION_RDY;
859 }
860 }
861
862 //*****************************************************************************
863 //
864 // Check if an array consists only of zeros.
865 //
866 //*****************************************************************************
PKAArrayAllZeros(const uint8_t * array,uint32_t arrayLength)867 bool PKAArrayAllZeros(const uint8_t *array, uint32_t arrayLength)
868 {
869 uint32_t i;
870 uint8_t arrayBits = 0;
871
872 // We could speed things up by comparing word-wise rather than byte-wise.
873 // However, this extra overhead is inconsequential compared to running an
874 // actual PKA operation. Especially ECC operations.
875 for (i = 0; i < arrayLength; i++) {
876 arrayBits |= array[i];
877 }
878
879 if (arrayBits) {
880 return false;
881 }
882 else {
883 return true;
884 }
885
886 }
887
888 //*****************************************************************************
889 //
890 // Fill an array with zeros
891 //
892 //*****************************************************************************
PKAZeroOutArray(const uint8_t * array,uint32_t arrayLength)893 void PKAZeroOutArray(const uint8_t *array, uint32_t arrayLength)
894 {
895 uint32_t i;
896 // Take the floor of paramLength in 32-bit words
897 uint32_t arrayLengthInWords = arrayLength / sizeof(uint32_t);
898
899 // Zero-out the array word-wise until i >= arrayLength
900 for (i = 0; i < arrayLengthInWords * sizeof(uint32_t); i += 4) {
901 HWREG(array + i) = 0;
902 }
903
904 // If i != arrayLength, there are some remaining bytes to zero-out
905 if (arrayLength % sizeof(uint32_t)) {
906 // Subtract 4 from i, since i has already overshot the array
907 for (i -= 4; i < arrayLength; i++) {
908 HWREGB(array + i * sizeof(uint32_t));
909 }
910 }
911 }
912
913 //*****************************************************************************
914 //
915 // Start the big number modulus operation.
916 //
917 //*****************************************************************************
PKABigNumModStart(const uint8_t * bigNum,uint32_t bigNumLength,const uint8_t * modulus,uint32_t modulusLength,uint32_t * resultPKAMemAddr)918 uint32_t PKABigNumModStart(const uint8_t *bigNum, uint32_t bigNumLength, const uint8_t *modulus, uint32_t modulusLength, uint32_t *resultPKAMemAddr)
919 {
920 uint32_t offset = 0;
921
922 // Check the arguments.
923 ASSERT(bigNum);
924 ASSERT(modulus);
925 ASSERT(resultPKAMemAddr);
926
927 // Make sure no operation is in progress.
928 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
929 return PKA_STATUS_OPERATION_BUSY;
930 }
931
932 offset = PKAWritePkaParam(bigNum, bigNumLength, offset, PKA_O_APTR);
933
934 offset = PKAWritePkaParamExtraOffset(modulus, modulusLength, offset, PKA_O_BPTR);
935
936 // Copy the result vector address location.
937 *resultPKAMemAddr = PKA_RAM_BASE + offset;
938
939 // Load C pointer with the result location in PKA RAM
940 HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
941
942 // Start the PKCP modulo operation by setting the PKA Function register.
943 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MODULO);
944
945 return PKA_STATUS_SUCCESS;
946 }
947
948 //*****************************************************************************
949 //
950 // Get the result of the big number modulus operation.
951 //
952 //*****************************************************************************
PKABigNumModGetResult(uint8_t * resultBuf,uint32_t length,uint32_t resultPKAMemAddr)953 uint32_t PKABigNumModGetResult(uint8_t *resultBuf, uint32_t length, uint32_t resultPKAMemAddr)
954 {
955 // Zero-out array in case modulo result is shorter than length
956 PKAZeroOutArray(resultBuf, length);
957
958 return PKAGetBigNumResultRemainder(resultBuf, &length, resultPKAMemAddr);
959 }
960
961 //*****************************************************************************
962 //
963 // Start the big number divide operation.
964 //
965 //*****************************************************************************
PKABigNumDivideStart(const uint8_t * dividend,uint32_t dividendLength,const uint8_t * divisor,uint32_t divisorLength,uint32_t * resultQuotientMemAddr,uint32_t * resultRemainderMemAddr)966 uint32_t PKABigNumDivideStart(const uint8_t *dividend, uint32_t dividendLength, const uint8_t *divisor, uint32_t divisorLength, uint32_t *resultQuotientMemAddr, uint32_t *resultRemainderMemAddr)
967 {
968 uint32_t offset = 0;
969
970 // Check the arguments.
971 ASSERT(dividend);
972 ASSERT(divisor);
973 ASSERT(resultQuotientMemAddr);
974 ASSERT(resultRemainderMemAddr);
975
976 // Make sure no operation is in progress.
977 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
978 return PKA_STATUS_OPERATION_BUSY;
979 }
980
981 offset = PKAWritePkaParam(dividend, dividendLength, offset, PKA_O_APTR);
982
983 offset = PKAWritePkaParamExtraOffset(divisor, divisorLength, offset, PKA_O_BPTR);
984
985 // Copy the remainder result vector address location.
986 if (resultRemainderMemAddr) {
987 *resultRemainderMemAddr = PKA_RAM_BASE + offset;
988 }
989
990 // The remainder cannot ever be larger than the divisor. It should fit inside
991 // a buffer of that size.
992 offset = PKAWritePkaParamExtraOffset(0, divisorLength, offset, PKA_O_CPTR);
993
994 // Copy the remainder result vector address location.
995 if (resultQuotientMemAddr) {
996 *resultQuotientMemAddr = PKA_RAM_BASE + offset;
997 }
998
999 // Load D pointer with the quotient location in PKA RAM
1000 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1001
1002 // Start the PKCP modulo operation by setting the PKA Function register.
1003 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_DIVIDE);
1004
1005 return PKA_STATUS_SUCCESS;
1006 }
1007
1008 //*****************************************************************************
1009 //
1010 // Get the quotient of the big number divide operation.
1011 //
1012 //*****************************************************************************
PKABigNumDivideGetQuotient(uint8_t * resultBuf,uint32_t * length,uint32_t resultQuotientMemAddr)1013 uint32_t PKABigNumDivideGetQuotient(uint8_t *resultBuf, uint32_t *length, uint32_t resultQuotientMemAddr)
1014 {
1015 return PKAGetBigNumResult(resultBuf, length, resultQuotientMemAddr);
1016 }
1017
1018 //*****************************************************************************
1019 //
1020 // Get the remainder of the big number divide operation.
1021 //
1022 //*****************************************************************************
PKABigNumDivideGetRemainder(uint8_t * resultBuf,uint32_t * length,uint32_t resultQuotientMemAddr)1023 uint32_t PKABigNumDivideGetRemainder(uint8_t *resultBuf, uint32_t *length, uint32_t resultQuotientMemAddr)
1024 {
1025 return PKAGetBigNumResultRemainder(resultBuf, length, resultQuotientMemAddr);
1026 }
1027
1028
1029 //*****************************************************************************
1030 //
1031 // Start the comparison of two big numbers.
1032 //
1033 //*****************************************************************************
PKABigNumCmpStart(const uint8_t * bigNum1,const uint8_t * bigNum2,uint32_t length)1034 uint32_t PKABigNumCmpStart(const uint8_t *bigNum1, const uint8_t *bigNum2, uint32_t length)
1035 {
1036 uint32_t offset = 0;
1037
1038 // Check the arguments.
1039 ASSERT(bigNum1);
1040 ASSERT(bigNum2);
1041
1042 // Make sure no operation is in progress.
1043 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1044 return PKA_STATUS_OPERATION_BUSY;
1045 }
1046
1047 offset = PKAWritePkaParam(bigNum1, length, offset, PKA_O_APTR);
1048
1049 offset = PKAWritePkaParam(bigNum2, length, offset, PKA_O_BPTR);
1050
1051 // Set the PKA Function register for the Compare operation
1052 // and start the operation.
1053 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_COMPARE);
1054
1055 return PKA_STATUS_SUCCESS;
1056 }
1057
1058 //*****************************************************************************
1059 //
1060 // Get the result of the comparison operation of two big numbers.
1061 //
1062 //*****************************************************************************
PKABigNumCmpGetResult(void)1063 uint32_t PKABigNumCmpGetResult(void)
1064 {
1065 uint32_t status;
1066
1067 // verify that the operation is complete.
1068 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1069 return PKA_STATUS_OPERATION_BUSY;
1070 }
1071
1072 // Check the COMPARE register.
1073 switch(HWREG(PKA_BASE + PKA_O_COMPARE)) {
1074 case PKA_COMPARE_A_EQUALS_B:
1075 status = PKA_STATUS_EQUAL;
1076 break;
1077
1078 case PKA_COMPARE_A_GREATER_THAN_B:
1079 status = PKA_STATUS_A_GREATER_THAN_B;
1080 break;
1081
1082 case PKA_COMPARE_A_LESS_THAN_B:
1083 status = PKA_STATUS_A_LESS_THAN_B;
1084 break;
1085
1086 default:
1087 status = PKA_STATUS_FAILURE;
1088 break;
1089 }
1090
1091 return status;
1092 }
1093
1094 //*****************************************************************************
1095 //
1096 // Start the big number inverse modulo operation.
1097 //
1098 //*****************************************************************************
PKABigNumInvModStart(const uint8_t * bigNum,uint32_t bigNumLength,const uint8_t * modulus,uint32_t modulusLength,uint32_t * resultPKAMemAddr)1099 uint32_t PKABigNumInvModStart(const uint8_t *bigNum, uint32_t bigNumLength, const uint8_t *modulus, uint32_t modulusLength, uint32_t *resultPKAMemAddr)
1100 {
1101 uint32_t offset = 0;
1102
1103 // Check the arguments.
1104 ASSERT(bigNum);
1105 ASSERT(modulus);
1106 ASSERT(resultPKAMemAddr);
1107
1108 // Make sure no operation is in progress.
1109 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1110 return PKA_STATUS_OPERATION_BUSY;
1111 }
1112
1113 offset = PKAWritePkaParam(bigNum, bigNumLength, offset, PKA_O_APTR);
1114
1115 offset = PKAWritePkaParam(modulus, modulusLength, offset, PKA_O_BPTR);
1116
1117 // Copy the result vector address location.
1118 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1119
1120 // Load D pointer with the result location in PKA RAM.
1121 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1122
1123 // set the PKA function to InvMod operation and the start the operation.
1124 HWREG(PKA_BASE + PKA_O_FUNCTION) = 0x0000F000;
1125
1126 return PKA_STATUS_SUCCESS;
1127 }
1128
1129 //*****************************************************************************
1130 //
1131 // Get the result of the big number inverse modulo operation.
1132 //
1133 //*****************************************************************************
PKABigNumInvModGetResult(uint8_t * resultBuf,uint32_t length,uint32_t resultPKAMemAddr)1134 uint32_t PKABigNumInvModGetResult(uint8_t *resultBuf, uint32_t length, uint32_t resultPKAMemAddr)
1135 {
1136 // Zero-out array in case modulo result is shorter than length
1137 PKAZeroOutArray(resultBuf, length);
1138
1139 return PKAGetBigNumResult(resultBuf, &length, resultPKAMemAddr);
1140 }
1141
1142 //*****************************************************************************
1143 //
1144 // Start the big number multiplication.
1145 //
1146 //*****************************************************************************
PKABigNumMultiplyStart(const uint8_t * multiplicand,uint32_t multiplicandLength,const uint8_t * multiplier,uint32_t multiplierLength,uint32_t * resultPKAMemAddr)1147 uint32_t PKABigNumMultiplyStart(const uint8_t *multiplicand, uint32_t multiplicandLength, const uint8_t *multiplier, uint32_t multiplierLength, uint32_t *resultPKAMemAddr)
1148 {
1149 uint32_t offset = 0;
1150
1151 // Check for the arguments.
1152 ASSERT(multiplicand);
1153 ASSERT(multiplier);
1154 ASSERT(resultPKAMemAddr);
1155
1156 // Make sure no operation is in progress.
1157 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1158 return PKA_STATUS_OPERATION_BUSY;
1159 }
1160
1161 offset = PKAWritePkaParam(multiplicand, multiplicandLength, offset, PKA_O_APTR);
1162
1163 offset = PKAWritePkaParam(multiplier, multiplierLength, offset, PKA_O_BPTR);
1164
1165
1166 // Copy the result vector address location.
1167 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1168
1169 // Load C pointer with the result location in PKA RAM.
1170 HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
1171
1172 // Set the PKA function to the multiplication and start it.
1173 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MULTIPLY);
1174
1175 return PKA_STATUS_SUCCESS;
1176 }
1177
1178 //*****************************************************************************
1179 //
1180 // Get the results of the big number multiplication.
1181 //
1182 //*****************************************************************************
PKABigNumMultGetResult(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)1183 uint32_t PKABigNumMultGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
1184 {
1185 return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
1186 }
1187
1188 //*****************************************************************************
1189 //
1190 // Start the addition of two big number.
1191 //
1192 //*****************************************************************************
PKABigNumAddStart(const uint8_t * bigNum1,uint32_t bigNum1Length,const uint8_t * bigNum2,uint32_t bigNum2Length,uint32_t * resultPKAMemAddr)1193 uint32_t PKABigNumAddStart(const uint8_t *bigNum1, uint32_t bigNum1Length, const uint8_t *bigNum2, uint32_t bigNum2Length, uint32_t *resultPKAMemAddr)
1194 {
1195 uint32_t offset = 0;
1196
1197 // Check for arguments.
1198 ASSERT(bigNum1);
1199 ASSERT(bigNum2);
1200 ASSERT(resultPKAMemAddr);
1201
1202 // Make sure no operation is in progress.
1203 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1204 return PKA_STATUS_OPERATION_BUSY;
1205 }
1206
1207 offset = PKAWritePkaParam(bigNum1, bigNum1Length, offset, PKA_O_APTR);
1208
1209 offset = PKAWritePkaParam(bigNum2, bigNum2Length, offset, PKA_O_BPTR);
1210
1211 // Copy the result vector address location.
1212 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1213
1214 // Load C pointer with the result location in PKA RAM.
1215 HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
1216
1217 // Set the function for the add operation and start the operation.
1218 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_ADD);
1219
1220 return PKA_STATUS_SUCCESS;
1221 }
1222
1223 //*****************************************************************************
1224 //
1225 // Get the result of the addition operation on two big number.
1226 //
1227 //*****************************************************************************
PKABigNumSubGetResult(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)1228 uint32_t PKABigNumSubGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
1229 {
1230 return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
1231 }
1232
1233 //*****************************************************************************
1234 //
1235 // Start the addition of two big number.
1236 //
1237 //*****************************************************************************
PKABigNumSubStart(const uint8_t * minuend,uint32_t minuendLength,const uint8_t * subtrahend,uint32_t subtrahendLength,uint32_t * resultPKAMemAddr)1238 uint32_t PKABigNumSubStart(const uint8_t *minuend, uint32_t minuendLength, const uint8_t *subtrahend, uint32_t subtrahendLength, uint32_t *resultPKAMemAddr)
1239 {
1240 uint32_t offset = 0;
1241
1242 // Check for arguments.
1243 ASSERT(minuend);
1244 ASSERT(subtrahend);
1245 ASSERT(resultPKAMemAddr);
1246
1247
1248 // Make sure no operation is in progress.
1249 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1250 return PKA_STATUS_OPERATION_BUSY;
1251 }
1252
1253 offset = PKAWritePkaParam(minuend, minuendLength, offset, PKA_O_APTR);
1254
1255 offset = PKAWritePkaParam(subtrahend, subtrahendLength, offset, PKA_O_BPTR);
1256
1257 // Copy the result vector address location.
1258 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1259
1260 // Load C pointer with the result location in PKA RAM.
1261 HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
1262
1263 // Set the function for the add operation and start the operation.
1264 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_SUBTRACT);
1265
1266 return PKA_STATUS_SUCCESS;
1267 }
1268
1269 //*****************************************************************************
1270 //
1271 // Get the result of the addition operation on two big number.
1272 //
1273 //*****************************************************************************
PKABigNumAddGetResult(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)1274 uint32_t PKABigNumAddGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
1275 {
1276 return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
1277 }
1278
1279
1280 //*****************************************************************************
1281 //
1282 // Start ECC Multiplication.
1283 //
1284 //*****************************************************************************
PKAEccMultiplyStart(const uint8_t * scalar,const uint8_t * curvePointX,const uint8_t * curvePointY,const uint8_t * prime,const uint8_t * a,const uint8_t * b,uint32_t length,uint32_t * resultPKAMemAddr)1285 uint32_t PKAEccMultiplyStart(const uint8_t *scalar, const uint8_t *curvePointX, const uint8_t *curvePointY, const uint8_t *prime, const uint8_t *a, const uint8_t *b, uint32_t length, uint32_t *resultPKAMemAddr)
1286 {
1287 uint32_t offset = 0;
1288
1289 // Check for the arguments.
1290 ASSERT(scalar);
1291 ASSERT(curvePointX);
1292 ASSERT(curvePointY);
1293 ASSERT(prime);
1294 ASSERT(a);
1295 ASSERT(b);
1296 ASSERT(length <= PKA_MAX_CURVE_SIZE_32_BIT_WORD * sizeof(uint32_t));
1297 ASSERT(resultPKAMemAddr);
1298
1299 // Make sure no PKA operation is in progress.
1300 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1301 return PKA_STATUS_OPERATION_BUSY;
1302 }
1303
1304 offset = PKAWritePkaParam(scalar, length, offset, PKA_O_APTR);
1305
1306 offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
1307 offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
1308 offset = PKAWritePkaParamExtraOffset(b, length, offset, PKA_NO_POINTER_REG);
1309
1310 offset = PKAWritePkaParamExtraOffset(curvePointX, length, offset, PKA_O_CPTR);
1311 offset = PKAWritePkaParamExtraOffset(curvePointY, length, offset, PKA_NO_POINTER_REG);
1312
1313 // Update the result location.
1314 // The resultPKAMemAddr may be 0 if we only want to check that we generated the point at infinity
1315 if (resultPKAMemAddr) {
1316 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1317 }
1318
1319 // Load D pointer with the result location in PKA RAM.
1320 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1321
1322 // Set the PKA function to ECC-MULT and start the operation.
1323 HWREG(PKA_BASE + PKA_O_FUNCTION) = PKA_FUNCTION_RUN_M | (0x05 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
1324
1325 return PKA_STATUS_SUCCESS;
1326 }
1327
1328
1329 //*****************************************************************************
1330 //
1331 // Start ECC Montgomery Multiplication.
1332 //
1333 //*****************************************************************************
PKAEccMontgomeryMultiplyStart(const uint8_t * scalar,const uint8_t * curvePointX,const uint8_t * prime,const uint8_t * a,uint32_t length,uint32_t * resultPKAMemAddr)1334 uint32_t PKAEccMontgomeryMultiplyStart(const uint8_t *scalar, const uint8_t *curvePointX, const uint8_t *prime, const uint8_t *a, uint32_t length, uint32_t *resultPKAMemAddr)
1335 {
1336 uint32_t offset = 0;
1337
1338 // Check for the arguments.
1339 ASSERT(scalar);
1340 ASSERT(curvePointX);
1341 ASSERT(prime);
1342 ASSERT(a);
1343 ASSERT(length <= PKA_MAX_CURVE_SIZE_32_BIT_WORD * sizeof(uint32_t));
1344 ASSERT(resultPKAMemAddr);
1345
1346 // Make sure no PKA operation is in progress.
1347 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1348 return PKA_STATUS_OPERATION_BUSY;
1349 }
1350
1351 offset = PKAWritePkaParam(scalar, length, offset, PKA_O_APTR);
1352
1353 offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
1354 offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
1355
1356 offset = PKAWritePkaParamExtraOffset(curvePointX, length, offset, PKA_O_CPTR);
1357
1358 // Update the result location.
1359 // The resultPKAMemAddr may be 0 if we only want to check that we generated the point at infinity
1360 if (resultPKAMemAddr) {
1361 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1362 }
1363
1364 // Load D pointer with the result location in PKA RAM.
1365 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1366
1367 // Set the PKA function to Montgomery ECC-MULT and start the operation.
1368 HWREG(PKA_BASE + PKA_O_FUNCTION) = PKA_FUNCTION_RUN_M | (0x02 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
1369
1370 return PKA_STATUS_SUCCESS;
1371 }
1372
1373
1374 //*****************************************************************************
1375 //
1376 // Get the result of ECC Multiplication
1377 //
1378 //*****************************************************************************
PKAEccMultiplyGetResult(uint8_t * curvePointX,uint8_t * curvePointY,uint32_t resultPKAMemAddr,uint32_t length)1379 uint32_t PKAEccMultiplyGetResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
1380 {
1381 return PKAGetECCResult(curvePointX, curvePointY, resultPKAMemAddr, length);
1382 }
1383
1384 //*****************************************************************************
1385 //
1386 // Start the ECC Addition.
1387 //
1388 //*****************************************************************************
PKAEccAddStart(const uint8_t * curvePoint1X,const uint8_t * curvePoint1Y,const uint8_t * curvePoint2X,const uint8_t * curvePoint2Y,const uint8_t * prime,const uint8_t * a,uint32_t length,uint32_t * resultPKAMemAddr)1389 uint32_t PKAEccAddStart(const uint8_t *curvePoint1X, const uint8_t *curvePoint1Y, const uint8_t *curvePoint2X, const uint8_t *curvePoint2Y, const uint8_t *prime, const uint8_t *a, uint32_t length, uint32_t *resultPKAMemAddr)
1390 {
1391 uint32_t offset = 0;
1392
1393 // Check for the arguments.
1394 ASSERT(curvePoint1X);
1395 ASSERT(curvePoint1Y);
1396 ASSERT(curvePoint2X);
1397 ASSERT(curvePoint2Y);
1398 ASSERT(prime);
1399 ASSERT(a);
1400 ASSERT(resultPKAMemAddr);
1401
1402 // Make sure no operation is in progress.
1403 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1404 return PKA_STATUS_OPERATION_BUSY;
1405 }
1406
1407 offset = PKAWritePkaParamExtraOffset(curvePoint1X, length, offset, PKA_O_APTR);
1408 offset = PKAWritePkaParamExtraOffset(curvePoint1Y, length, offset, PKA_NO_POINTER_REG);
1409
1410
1411 offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
1412 offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
1413
1414 offset = PKAWritePkaParamExtraOffset(curvePoint2X, length, offset, PKA_O_CPTR);
1415 offset = PKAWritePkaParamExtraOffset(curvePoint2Y, length, offset, PKA_NO_POINTER_REG);
1416
1417 // Copy the result vector location.
1418 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1419
1420 // Load D pointer with the result location in PKA RAM.
1421 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1422
1423 // Set the PKA Function to ECC-ADD and start the operation.
1424 HWREG(PKA_BASE + PKA_O_FUNCTION ) = PKA_FUNCTION_RUN_M | (0x03 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
1425
1426 return PKA_STATUS_SUCCESS;
1427 }
1428
1429 //*****************************************************************************
1430 //
1431 // Get the result of the ECC Addition
1432 //
1433 //*****************************************************************************
PKAEccAddGetResult(uint8_t * curvePointX,uint8_t * curvePointY,uint32_t resultPKAMemAddr,uint32_t length)1434 uint32_t PKAEccAddGetResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
1435 {
1436 return PKAGetECCResult(curvePointX, curvePointY, resultPKAMemAddr, length);
1437 }
1438
1439 //*****************************************************************************
1440 //
1441 // Verify a public key against the supplied elliptic curve equation
1442 //
1443 //*****************************************************************************
PKAEccVerifyPublicKeyWeierstrassStart(const uint8_t * curvePointX,const uint8_t * curvePointY,const uint8_t * prime,const uint8_t * a,const uint8_t * b,const uint8_t * order,uint32_t length)1444 uint32_t PKAEccVerifyPublicKeyWeierstrassStart(const uint8_t *curvePointX, const uint8_t *curvePointY, const uint8_t *prime, const uint8_t *a, const uint8_t *b, const uint8_t *order, uint32_t length)
1445 {
1446 uint32_t pkaResult;
1447 uint32_t resultAddress;
1448 uint32_t resultLength;
1449 uint8_t *scratchBuffer = (uint8_t *)(PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE / 2);
1450 uint8_t *scratchBuffer2 = scratchBuffer + 512;
1451
1452
1453 // Verify X in range [0, prime - 1]
1454 PKABigNumCmpStart(curvePointX,
1455 prime,
1456 length);
1457
1458 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1459
1460 pkaResult = PKABigNumCmpGetResult();
1461
1462 if (pkaResult != PKA_STATUS_A_LESS_THAN_B) {
1463 return PKA_STATUS_X_LARGER_THAN_PRIME;
1464 }
1465
1466 // Verify Y in range [0, prime - 1]
1467 PKABigNumCmpStart(curvePointY,
1468 prime,
1469 length);
1470
1471 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1472
1473 pkaResult = PKABigNumCmpGetResult();
1474
1475 if (pkaResult != PKA_STATUS_A_LESS_THAN_B) {
1476 return PKA_STATUS_Y_LARGER_THAN_PRIME;
1477 }
1478
1479 // Verify point on curve
1480 // Short-Weierstrass equation: Y ^ 2 = X ^3 + a * X + b mod P
1481 // Reduced: Y ^ 2 = X * (X ^ 2 + a) + b
1482
1483 // tmp = X ^ 2
1484 PKABigNumMultiplyStart(curvePointX, length, curvePointX, length, &resultAddress);
1485
1486 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1487
1488 resultLength = 200;
1489 pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
1490
1491 if (pkaResult != PKA_STATUS_SUCCESS) {
1492 return PKA_STATUS_FAILURE;
1493 }
1494
1495 // tmp += a
1496 PKABigNumAddStart(scratchBuffer, resultLength, a, length, &resultAddress);
1497
1498 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1499
1500 resultLength = 200;
1501 pkaResult = PKABigNumAddGetResult(scratchBuffer, &resultLength, resultAddress);
1502
1503 if (pkaResult != PKA_STATUS_SUCCESS) {
1504 return PKA_STATUS_FAILURE;
1505 }
1506
1507 // tmp *= x
1508 PKABigNumMultiplyStart(scratchBuffer, resultLength, curvePointX, length, &resultAddress);
1509
1510 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1511
1512 resultLength = 200;
1513 pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
1514
1515 if (pkaResult != PKA_STATUS_SUCCESS) {
1516 return PKA_STATUS_FAILURE;
1517 }
1518
1519 // tmp += b
1520 PKABigNumAddStart(scratchBuffer, resultLength, b, length, &resultAddress);
1521
1522 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1523
1524 resultLength = 200;
1525 pkaResult = PKABigNumAddGetResult(scratchBuffer, &resultLength, resultAddress);
1526
1527 if (pkaResult != PKA_STATUS_SUCCESS) {
1528 return PKA_STATUS_FAILURE;
1529 }
1530
1531
1532 // tmp2 = tmp % prime to ensure we have no fraction in the division.
1533 // The number will only shrink from here on out.
1534 PKABigNumModStart(scratchBuffer, resultLength, prime, length, &resultAddress);
1535
1536 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1537
1538 // If the result is not a multiple of the word-length, the PKA HW will round up
1539 // because it deals in words only. That means that using 'length' directly
1540 // would cause and underflow, since length refers to the actual length in bytes of
1541 // the curve parameters while the PKA HW reports that rounded up to the next
1542 // word boundary.
1543 // Use 200 as the resultLength instead since we are copying to the scratch buffer
1544 // anyway.
1545 // Practically, this only happens with curves such as NIST-P521 that are not word
1546 // multiples.
1547 resultLength = 200;
1548 pkaResult = PKABigNumModGetResult(scratchBuffer2, resultLength, resultAddress);
1549
1550 if (pkaResult != PKA_STATUS_SUCCESS) {
1551 return PKA_STATUS_FAILURE;
1552 }
1553
1554 // tmp = y^2
1555 PKABigNumMultiplyStart(curvePointY, length, curvePointY, length, &resultAddress);
1556
1557 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1558
1559 resultLength = 200;
1560 pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
1561
1562 if (pkaResult != PKA_STATUS_SUCCESS) {
1563 return PKA_STATUS_FAILURE;
1564 }
1565
1566 // tmp %= prime
1567 PKABigNumModStart(scratchBuffer, resultLength, prime, length, &resultAddress);
1568
1569 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1570
1571 // If the result is not a multiple of the word-length, the PKA HW will round up
1572 // because it deals in words only. That means that using 'length' directly
1573 // would cause and underflow, since length refers to the actual length in bytes of
1574 // the curve parameters while the PKA HW reports that rounded up to the next
1575 // word boundary.
1576 // Use 200 as the resultLength instead since we are copying to the scratch buffer
1577 // anyway.
1578 // Practically, this only happens with curves such as NIST-P521 that are not word
1579 // multiples.
1580 resultLength = 200;
1581 pkaResult = PKABigNumModGetResult(scratchBuffer, resultLength, resultAddress);
1582
1583 if (pkaResult != PKA_STATUS_SUCCESS) {
1584 return PKA_STATUS_FAILURE;
1585 }
1586
1587 // tmp ?= tmp2
1588 PKABigNumCmpStart(scratchBuffer,
1589 scratchBuffer2,
1590 length);
1591
1592 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1593
1594 pkaResult = PKABigNumCmpGetResult();
1595
1596 if (pkaResult != PKA_STATUS_EQUAL) {
1597 return PKA_STATUS_POINT_NOT_ON_CURVE;
1598 }
1599 else {
1600 return PKA_STATUS_SUCCESS;
1601 }
1602 }
1603