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