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