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