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