blob: 57e4b58182c536bc5ecf558f7420d879dacab5f6 [file] [log] [blame]
/******************************************************************************
* Filename: pka.c
* Revised: 2018-07-19 15:07:05 +0200 (Thu, 19 Jul 2018)
* Revision: 52294
*
* Description: Driver for the PKA module
*
* Copyright (c) 2015 - 2017, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of the ORGANIZATION nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
#include "pka.h"
//*****************************************************************************
//
// Handle support for DriverLib in ROM:
// This section will undo prototype renaming made in the header file
//
//*****************************************************************************
#if !defined(DOXYGEN)
#undef PKAClearPkaRam
#define PKAClearPkaRam NOROM_PKAClearPkaRam
#undef PKAGetOpsStatus
#define PKAGetOpsStatus NOROM_PKAGetOpsStatus
#undef PKAArrayAllZeros
#define PKAArrayAllZeros NOROM_PKAArrayAllZeros
#undef PKAZeroOutArray
#define PKAZeroOutArray NOROM_PKAZeroOutArray
#undef PKABigNumModStart
#define PKABigNumModStart NOROM_PKABigNumModStart
#undef PKABigNumModGetResult
#define PKABigNumModGetResult NOROM_PKABigNumModGetResult
#undef PKABigNumDivideStart
#define PKABigNumDivideStart NOROM_PKABigNumDivideStart
#undef PKABigNumDivideGetQuotient
#define PKABigNumDivideGetQuotient NOROM_PKABigNumDivideGetQuotient
#undef PKABigNumDivideGetRemainder
#define PKABigNumDivideGetRemainder NOROM_PKABigNumDivideGetRemainder
#undef PKABigNumCmpStart
#define PKABigNumCmpStart NOROM_PKABigNumCmpStart
#undef PKABigNumCmpGetResult
#define PKABigNumCmpGetResult NOROM_PKABigNumCmpGetResult
#undef PKABigNumInvModStart
#define PKABigNumInvModStart NOROM_PKABigNumInvModStart
#undef PKABigNumInvModGetResult
#define PKABigNumInvModGetResult NOROM_PKABigNumInvModGetResult
#undef PKABigNumMultiplyStart
#define PKABigNumMultiplyStart NOROM_PKABigNumMultiplyStart
#undef PKABigNumMultGetResult
#define PKABigNumMultGetResult NOROM_PKABigNumMultGetResult
#undef PKABigNumAddStart
#define PKABigNumAddStart NOROM_PKABigNumAddStart
#undef PKABigNumAddGetResult
#define PKABigNumAddGetResult NOROM_PKABigNumAddGetResult
#undef PKABigNumSubStart
#define PKABigNumSubStart NOROM_PKABigNumSubStart
#undef PKABigNumSubGetResult
#define PKABigNumSubGetResult NOROM_PKABigNumSubGetResult
#undef PKAEccMultiplyStart
#define PKAEccMultiplyStart NOROM_PKAEccMultiplyStart
#undef PKAEccMontgomeryMultiplyStart
#define PKAEccMontgomeryMultiplyStart NOROM_PKAEccMontgomeryMultiplyStart
#undef PKAEccMultiplyGetResult
#define PKAEccMultiplyGetResult NOROM_PKAEccMultiplyGetResult
#undef PKAEccAddStart
#define PKAEccAddStart NOROM_PKAEccAddStart
#undef PKAEccAddGetResult
#define PKAEccAddGetResult NOROM_PKAEccAddGetResult
#undef PKAEccVerifyPublicKeyWeierstrassStart
#define PKAEccVerifyPublicKeyWeierstrassStart NOROM_PKAEccVerifyPublicKeyWeierstrassStart
#endif
//*****************************************************************************
//
// Handle support for DriverLib in ROM:
// This section will undo prototype renaming made in the header file
//
//*****************************************************************************
#if !defined(DOXYGEN)
#undef PKAClearPkaRam
#define PKAClearPkaRam NOROM_PKAClearPkaRam
#undef PKAGetOpsStatus
#define PKAGetOpsStatus NOROM_PKAGetOpsStatus
#undef PKAArrayAllZeros
#define PKAArrayAllZeros NOROM_PKAArrayAllZeros
#undef PKAZeroOutArray
#define PKAZeroOutArray NOROM_PKAZeroOutArray
#undef PKABigNumModStart
#define PKABigNumModStart NOROM_PKABigNumModStart
#undef PKABigNumModGetResult
#define PKABigNumModGetResult NOROM_PKABigNumModGetResult
#undef PKABigNumDivideStart
#define PKABigNumDivideStart NOROM_PKABigNumDivideStart
#undef PKABigNumDivideGetQuotient
#define PKABigNumDivideGetQuotient NOROM_PKABigNumDivideGetQuotient
#undef PKABigNumDivideGetRemainder
#define PKABigNumDivideGetRemainder NOROM_PKABigNumDivideGetRemainder
#undef PKABigNumCmpStart
#define PKABigNumCmpStart NOROM_PKABigNumCmpStart
#undef PKABigNumCmpGetResult
#define PKABigNumCmpGetResult NOROM_PKABigNumCmpGetResult
#undef PKABigNumInvModStart
#define PKABigNumInvModStart NOROM_PKABigNumInvModStart
#undef PKABigNumInvModGetResult
#define PKABigNumInvModGetResult NOROM_PKABigNumInvModGetResult
#undef PKABigNumMultiplyStart
#define PKABigNumMultiplyStart NOROM_PKABigNumMultiplyStart
#undef PKABigNumMultGetResult
#define PKABigNumMultGetResult NOROM_PKABigNumMultGetResult
#undef PKABigNumAddStart
#define PKABigNumAddStart NOROM_PKABigNumAddStart
#undef PKABigNumAddGetResult
#define PKABigNumAddGetResult NOROM_PKABigNumAddGetResult
#undef PKABigNumSubStart
#define PKABigNumSubStart NOROM_PKABigNumSubStart
#undef PKABigNumSubGetResult
#define PKABigNumSubGetResult NOROM_PKABigNumSubGetResult
#undef PKAEccMultiplyStart
#define PKAEccMultiplyStart NOROM_PKAEccMultiplyStart
#undef PKAEccMontgomeryMultiplyStart
#define PKAEccMontgomeryMultiplyStart NOROM_PKAEccMontgomeryMultiplyStart
#undef PKAEccMultiplyGetResult
#define PKAEccMultiplyGetResult NOROM_PKAEccMultiplyGetResult
#undef PKAEccAddStart
#define PKAEccAddStart NOROM_PKAEccAddStart
#undef PKAEccAddGetResult
#define PKAEccAddGetResult NOROM_PKAEccAddGetResult
#undef PKAEccVerifyPublicKeyWeierstrassStart
#define PKAEccVerifyPublicKeyWeierstrassStart NOROM_PKAEccVerifyPublicKeyWeierstrassStart
#endif
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define INRANGE(x,y,z) ((x) > (y) && (x) < (z))
//*****************************************************************************
//
// Define for the maximum curve size supported by the PKA module in 32 bit
// word.
// \note PKA hardware module can support up to 384 bit curve size due to the
// 2K of PKA RAM.
//
//*****************************************************************************
#define PKA_MAX_CURVE_SIZE_32_BIT_WORD 12
//*****************************************************************************
//
// Define for the maximum length of the big number supported by the PKA module
// in 32 bit word.
//
//*****************************************************************************
#define PKA_MAX_LEN_IN_32_BIT_WORD PKA_MAX_CURVE_SIZE_32_BIT_WORD
//*****************************************************************************
//
// Used in PKAWritePkaParam() and PKAWritePkaParamExtraOffset() to specify that
// the base address of the parameter should not be written to a NPTR register.
//
//*****************************************************************************
#define PKA_NO_POINTER_REG 0xFF
//*****************************************************************************
//
// NIST P224 constants in little endian format. byte[0] is the least
// significant byte and byte[NISTP224_PARAM_SIZE_BYTES - 1] is the most
// significant.
//
//*****************************************************************************
const PKA_EccPoint224 NISTP224_generator = {
.x = {.byte = {0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34,
0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A,
0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B,
0xBD, 0x0C, 0x0E, 0xB7, }},
.y = {.byte = {0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44,
0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD,
0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5,
0x88, 0x63, 0x37, 0xBD, }},
};
const PKA_EccParam224 NISTP224_prime = {.byte = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF}};
const PKA_EccParam224 NISTP224_a = {.byte = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF}};
const PKA_EccParam224 NISTP224_b = {.byte = {0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27,
0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50,
0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C,
0x85, 0x0A, 0x05, 0xB4}};
const PKA_EccParam224 NISTP224_order = {.byte = {0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13,
0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF}};
//*****************************************************************************
//
// NIST P256 constants in little endian format. byte[0] is the least
// significant byte and byte[NISTP256_PARAM_SIZE_BYTES - 1] is the most
// significant.
//
//*****************************************************************************
const PKA_EccPoint256 NISTP256_generator = {
.x = {.byte = {0x96, 0xc2, 0x98, 0xd8, 0x45, 0x39, 0xa1, 0xf4,
0xa0, 0x33, 0xeb, 0x2d, 0x81, 0x7d, 0x03, 0x77,
0xf2, 0x40, 0xa4, 0x63, 0xe5, 0xe6, 0xbc, 0xf8,
0x47, 0x42, 0x2c, 0xe1, 0xf2, 0xd1, 0x17, 0x6b}},
.y = {.byte = {0xf5, 0x51, 0xbf, 0x37, 0x68, 0x40, 0xb6, 0xcb,
0xce, 0x5e, 0x31, 0x6b, 0x57, 0x33, 0xce, 0x2b,
0x16, 0x9e, 0x0f, 0x7c, 0x4a, 0xeb, 0xe7, 0x8e,
0x9b, 0x7f, 0x1a, 0xfe, 0xe2, 0x42, 0xe3, 0x4f}},
};
const PKA_EccParam256 NISTP256_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
const PKA_EccParam256 NISTP256_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
const PKA_EccParam256 NISTP256_b = {.byte = {0x4b, 0x60, 0xd2, 0x27, 0x3e, 0x3c, 0xce, 0x3b,
0xf6, 0xb0, 0x53, 0xcc, 0xb0, 0x06, 0x1d, 0x65,
0xbc, 0x86, 0x98, 0x76, 0x55, 0xbd, 0xeb, 0xb3,
0xe7, 0x93, 0x3a, 0xaa, 0xd8, 0x35, 0xc6, 0x5a}};
const PKA_EccParam256 NISTP256_order = {.byte = {0x51, 0x25, 0x63, 0xfc, 0xc2, 0xca, 0xb9, 0xf3,
0x84, 0x9e, 0x17, 0xa7, 0xad, 0xfa, 0xe6, 0xbc,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
//*****************************************************************************
//
// NIST P384 constants in little endian format. byte[0] is the least
// significant byte and byte[NISTP384_PARAM_SIZE_BYTES - 1] is the most
// significant.
//
//*****************************************************************************
const PKA_EccPoint384 NISTP384_generator = {
.x = {.byte = {0xb7, 0x0a, 0x76, 0x72, 0x38, 0x5e, 0x54, 0x3a,
0x6c, 0x29, 0x55, 0xbf, 0x5d, 0xf2, 0x02, 0x55,
0x38, 0x2a, 0x54, 0x82, 0xe0, 0x41, 0xf7, 0x59,
0x98, 0x9b, 0xa7, 0x8b, 0x62, 0x3b, 0x1d, 0x6e,
0x74, 0xad, 0x20, 0xf3, 0x1e, 0xc7, 0xb1, 0x8e,
0x37, 0x05, 0x8b, 0xbe, 0x22, 0xca, 0x87, 0xaa}},
.y = {.byte = {0x5f, 0x0e, 0xea, 0x90, 0x7c, 0x1d, 0x43, 0x7a,
0x9d, 0x81, 0x7e, 0x1d, 0xce, 0xb1, 0x60, 0x0a,
0xc0, 0xb8, 0xf0, 0xb5, 0x13, 0x31, 0xda, 0xe9,
0x7c, 0x14, 0x9a, 0x28, 0xbd, 0x1d, 0xf4, 0xf8,
0x29, 0xdc, 0x92, 0x92, 0xbf, 0x98, 0x9e, 0x5d,
0x6f, 0x2c, 0x26, 0x96, 0x4a, 0xde, 0x17, 0x36,}},
};
const PKA_EccParam384 NISTP384_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
const PKA_EccParam384 NISTP384_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
const PKA_EccParam384 NISTP384_b = {.byte = {0xef, 0x2a, 0xec, 0xd3, 0xed, 0xc8, 0x85, 0x2a,
0x9d, 0xd1, 0x2e, 0x8a, 0x8d, 0x39, 0x56, 0xc6,
0x5a, 0x87, 0x13, 0x50, 0x8f, 0x08, 0x14, 0x03,
0x12, 0x41, 0x81, 0xfe, 0x6e, 0x9c, 0x1d, 0x18,
0x19, 0x2d, 0xf8, 0xe3, 0x6b, 0x05, 0x8e, 0x98,
0xe4, 0xe7, 0x3e, 0xe2, 0xa7, 0x2f, 0x31, 0xb3}};
const PKA_EccParam384 NISTP384_order = {.byte = {0x73, 0x29, 0xc5, 0xcc, 0x6a, 0x19, 0xec, 0xec,
0x7a, 0xa7, 0xb0, 0x48, 0xb2, 0x0d, 0x1a, 0x58,
0xdf, 0x2d, 0x37, 0xf4, 0x81, 0x4d, 0x63, 0xc7,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
//*****************************************************************************
//
// NIST P521 constants in little endian format. byte[0] is the least
// significant byte and byte[NISTP521_PARAM_SIZE_BYTES - 1] is the most
// significant.
//
//*****************************************************************************
const PKA_EccPoint521 NISTP521_generator = {
.x = {.byte = {0x66, 0xbd, 0xe5, 0xc2, 0x31, 0x7e, 0x7e, 0xf9,
0x9b, 0x42, 0x6a, 0x85, 0xc1, 0xb3, 0x48, 0x33,
0xde, 0xa8, 0xff, 0xa2, 0x27, 0xc1, 0x1d, 0xfe,
0x28, 0x59, 0xe7, 0xef, 0x77, 0x5e, 0x4b, 0xa1,
0xba, 0x3d, 0x4d, 0x6b, 0x60, 0xaf, 0x28, 0xf8,
0x21, 0xb5, 0x3f, 0x05, 0x39, 0x81, 0x64, 0x9c,
0x42, 0xb4, 0x95, 0x23, 0x66, 0xcb, 0x3e, 0x9e,
0xcd, 0xe9, 0x04, 0x04, 0xb7, 0x06, 0x8e, 0x85,
0xc6, 0x00}},
.y = {.byte = {0x50, 0x66, 0xd1, 0x9f, 0x76, 0x94, 0xbe, 0x88,
0x40, 0xc2, 0x72, 0xa2, 0x86, 0x70, 0x3c, 0x35,
0x61, 0x07, 0xad, 0x3f, 0x01, 0xb9, 0x50, 0xc5,
0x40, 0x26, 0xf4, 0x5e, 0x99, 0x72, 0xee, 0x97,
0x2c, 0x66, 0x3e, 0x27, 0x17, 0xbd, 0xaf, 0x17,
0x68, 0x44, 0x9b, 0x57, 0x49, 0x44, 0xf5, 0x98,
0xd9, 0x1b, 0x7d, 0x2c, 0xb4, 0x5f, 0x8a, 0x5c,
0x04, 0xc0, 0x3b, 0x9a, 0x78, 0x6a, 0x29, 0x39,
0x18, 0x01}},
};
const PKA_EccParam521 NISTP521_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x01}};
const PKA_EccParam521 NISTP521_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x01}};
const PKA_EccParam521 NISTP521_b = {.byte = {0x00, 0x3f, 0x50, 0x6b, 0xd4, 0x1f, 0x45, 0xef,
0xf1, 0x34, 0x2c, 0x3d, 0x88, 0xdf, 0x73, 0x35,
0x07, 0xbf, 0xb1, 0x3b, 0xbd, 0xc0, 0x52, 0x16,
0x7b, 0x93, 0x7e, 0xec, 0x51, 0x39, 0x19, 0x56,
0xe1, 0x09, 0xf1, 0x8e, 0x91, 0x89, 0xb4, 0xb8,
0xf3, 0x15, 0xb3, 0x99, 0x5b, 0x72, 0xda, 0xa2,
0xee, 0x40, 0x85, 0xb6, 0xa0, 0x21, 0x9a, 0x92,
0x1f, 0x9a, 0x1c, 0x8e, 0x61, 0xb9, 0x3e, 0x95,
0x51, 0x00}};
const PKA_EccParam521 NISTP521_order = {.byte = {0x09, 0x64, 0x38, 0x91, 0x1e, 0xb7, 0x6f, 0xbb,
0xae, 0x47, 0x9c, 0x89, 0xb8, 0xc9, 0xb5, 0x3b,
0xd0, 0xa5, 0x09, 0xf7, 0x48, 0x01, 0xcc, 0x7f,
0x6b, 0x96, 0x2f, 0xbf, 0x83, 0x87, 0x86, 0x51,
0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x01}};
//*****************************************************************************
//
// Brainpool P256r1 constants in little endian format. byte[0] is the least
// significant byte and byte[BrainpoolP256R1_PARAM_SIZE_BYTES - 1] is the most
// significant.
//
//*****************************************************************************
const PKA_EccPoint256 BrainpoolP256R1_generator = {
.x = {.byte = {0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A,
0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9,
0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C,
0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B}},
.y = {.byte = {0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C,
0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2,
0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97,
0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54}},
};
const PKA_EccParam256 BrainpoolP256R1_prime = {.byte = {0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20,
0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E,
0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E,
0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9}};
const PKA_EccParam256 BrainpoolP256R1_a = {.byte = {0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9,
0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB,
0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE,
0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D}};
const PKA_EccParam256 BrainpoolP256R1_b = {.byte = {0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B,
0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95,
0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3,
0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26,}};
const PKA_EccParam256 BrainpoolP256R1_order = {.byte = {0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90,
0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C,
0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E,
0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9}};
//*****************************************************************************
//
// Brainpool P384r1 constants in little endian format. byte[0] is the least
// significant byte and byte[BrainpoolP384R1_PARAM_SIZE_BYTES - 1] is the most
// significant.
//
//*****************************************************************************
const PKA_EccPoint384 BrainpoolP384R1_generator = {
.x = {.byte = {0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF,
0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8,
0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB,
0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88,
0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2,
0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D}},
.y = {.byte = {0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42,
0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E,
0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1,
0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62,
0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C,
0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A}},
};
const PKA_EccParam384 BrainpoolP384R1_prime = {.byte = {0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87,
0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC,
0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12,
0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15,
0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F,
0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C}};
const PKA_EccParam384 BrainpoolP384R1_a = {.byte = {0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04,
0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A,
0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13,
0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2,
0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C,
0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B}};
const PKA_EccParam384 BrainpoolP384R1_b = {.byte = {0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A,
0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C,
0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E,
0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F,
0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B,
0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04}};
const PKA_EccParam384 BrainpoolP384R1_order = {.byte = {0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B,
0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF,
0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F,
0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15,
0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F,
0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C}};
//*****************************************************************************
//
// Brainpool P512r1 constants in little endian format. byte[0] is the least
// significant byte and byte[BrainpoolP512R1_PARAM_SIZE_BYTES - 1] is the most
// significant.
//
//*****************************************************************************
const PKA_EccPoint512 BrainpoolP512R1_generator = {
.x = {.byte = {0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B,
0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C,
0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50,
0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF,
0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4,
0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85,
0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A,
0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81}},
.y = {.byte = {0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78,
0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1,
0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B,
0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2,
0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0,
0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2,
0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0,
0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D}},
};
const PKA_EccParam512 BrainpoolP512R1_prime = {.byte = {0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28,
0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28,
0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE,
0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D,
0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6,
0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB,
0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F,
0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA}};
const PKA_EccParam512 BrainpoolP512R1_a = {.byte = {0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7,
0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F,
0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A,
0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D,
0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8,
0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94,
0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2,
0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78}};
const PKA_EccParam512 BrainpoolP512R1_b = {.byte = {0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28,
0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98,
0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77,
0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B,
0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B,
0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8,
0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA,
0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D}};
const PKA_EccParam512 BrainpoolP512R1_order = {.byte = {0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5,
0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D,
0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41,
0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55,
0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6,
0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB,
0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F,
0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA}};
//*****************************************************************************
//
// Curve25519 constants in little endian format. byte[0] is the least
// significant byte and byte[Curve25519_PARAM_SIZE_BYTES - 1] is the most
// significant.
//
//*****************************************************************************
const PKA_EccPoint256 Curve25519_generator = {
.x = {.byte = {0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}},
.y = {.byte = {0xd9, 0xd3, 0xce, 0x7e, 0xa2, 0xc5, 0xe9, 0x29,
0xb2, 0x61, 0x7c, 0x6d, 0x7e, 0x4d, 0x3d, 0x92,
0x4c, 0xd1, 0x48, 0x77, 0x2c, 0xdd, 0x1e, 0xe0,
0xb4, 0x86, 0xa0, 0xb8, 0xa1, 0x19, 0xae, 0x20}},
};
const PKA_EccParam256 Curve25519_prime = {.byte = {0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}};
const PKA_EccParam256 Curve25519_a = {.byte = {0x06, 0x6d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
const PKA_EccParam256 Curve25519_b = {.byte = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
const PKA_EccParam256 Curve25519_order = {.byte = {0xb9, 0xdc, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
//*****************************************************************************
//
// Zeroize PKA RAM. Not threadsafe.
//
//*****************************************************************************
void PKAClearPkaRam(void){
// Get initial state
uint32_t secdmaclkgr = HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR);
// OR in zeroize bit
secdmaclkgr |= PRCM_SECDMACLKGR_PKA_ZERIOZE_RESET_N;
// Start zeroization
HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) = secdmaclkgr;
// Wait 256 cycles for PKA RAM to be cleared
CPUdelay(256 / 4);
// Turn off zeroization
HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) = secdmaclkgr & (~PRCM_SECDMACLKGR_PKA_ZERIOZE_RESET_N);
}
//*****************************************************************************
//
// Write a PKA parameter to the PKA module, set required registers, and add an offset.
//
//*****************************************************************************
static uint32_t PKAWritePkaParam(const uint8_t *param, uint32_t paramLength, uint32_t paramOffset, uint32_t ptrRegOffset)
{
uint32_t i;
uint32_t *paramWordAlias = (uint32_t *)param;
// Take the floor of paramLength in 32-bit words
uint32_t paramLengthInWords = paramLength / sizeof(uint32_t);
// Only copy data if it is specified. We may wish to simply allocate another buffer and get
// the required offset.
if (param) {
// Load the number in PKA RAM
for (i = 0; i < paramLengthInWords; i++) {
HWREG(PKA_RAM_BASE + paramOffset + sizeof(uint32_t) * i) = paramWordAlias[i];
}
// If the length is not a word-multiple, fill up a temporary word and copy that in
// to avoid a bus error. The extra zeros at the end should not matter, as the large
// number is little-endian and thus has no effect.
// We could have correctly calculated ceiling(paramLength / sizeof(uint32_t)) above.
// However, we would not have been able to zero-out the extra few most significant
// bytes of the most significant word. That would have resulted in doing maths operations
// on whatever follows param in RAM.
if (paramLength % sizeof(uint32_t)) {
uint32_t temp = 0;
uint8_t j;
// Load the entire word line of the param remainder
temp = paramWordAlias[i];
// Zero-out all bytes beyond the end of the param
for (j = paramLength % sizeof(uint32_t); j < sizeof(uint32_t); j++) {
((uint8_t *)&temp)[j] = 0;
}
HWREG(PKA_RAM_BASE + paramOffset + sizeof(uint32_t) * i) = temp;
// Increment paramLengthInWords since we take the ceiling of length / sizeof(uint32_t)
paramLengthInWords++;
}
}
// Update the A, B, C, or D pointer with the offset address of the PKA RAM location
// where the number will be stored.
switch (ptrRegOffset) {
case PKA_O_APTR:
HWREG(PKA_BASE + PKA_O_APTR) = paramOffset >> 2;
HWREG(PKA_BASE + PKA_O_ALENGTH) = paramLengthInWords;
break;
case PKA_O_BPTR:
HWREG(PKA_BASE + PKA_O_BPTR) = paramOffset >> 2;
HWREG(PKA_BASE + PKA_O_BLENGTH) = paramLengthInWords;
break;
case PKA_O_CPTR:
HWREG(PKA_BASE + PKA_O_CPTR) = paramOffset >> 2;
break;
case PKA_O_DPTR:
HWREG(PKA_BASE + PKA_O_DPTR) = paramOffset >> 2;
break;
}
// Ensure 8-byte alignment of next parameter.
// Returns the offset for the next parameter.
return paramOffset + sizeof(uint32_t) * (paramLengthInWords + (paramLengthInWords % 2));
}
//*****************************************************************************
//
// Write a PKA parameter to the PKA module but return a larger offset.
//
//*****************************************************************************
static uint32_t PKAWritePkaParamExtraOffset(const uint8_t *param, uint32_t paramLength, uint32_t paramOffset, uint32_t ptrRegOffset)
{
// Ensure 16-byte alignment.
return (sizeof(uint32_t) * 2) + PKAWritePkaParam(param, paramLength, paramOffset, ptrRegOffset);
}
//*****************************************************************************
//
// Writes the result of a large number arithmetic operation to a provided buffer.
//
//*****************************************************************************
static uint32_t PKAGetBigNumResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
{
uint32_t mswOffset;
uint32_t lswOffset;
uint32_t lengthInWords;
uint32_t i;
uint32_t *resultWordAlias = (uint32_t *)resultBuf;
// Check the arguments.
ASSERT(resultBuf);
ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
(resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
// Verify that the operation is complete.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
// Get the MSW register value.
mswOffset = HWREG(PKA_BASE + PKA_O_MSW);
// If the result vector is zero, write back one zero byte so the caller does not need
// to handle a special error for the perhaps valid result of zero.
// They will only get the error status if they do not provide a buffer
if (mswOffset & PKA_MSW_RESULT_IS_ZERO_M) {
if (*resultLength){
if(resultBuf){
resultBuf[0] = 0;
}
*resultLength = 1;
return PKA_STATUS_SUCCESS;
}
else {
return PKA_STATUS_BUF_UNDERFLOW;
}
}
// Get the length of the result
mswOffset = ((mswOffset & PKA_MSW_MSW_ADDRESS_M) + 1);
lswOffset = ((resultPKAMemAddr - PKA_RAM_BASE) >> 2);
if (mswOffset >= lswOffset) {
lengthInWords = mswOffset - lswOffset;
}
else {
return PKA_STATUS_RESULT_ADDRESS_INCORRECT;
}
// Check if the provided buffer length is adequate to store the result data.
if (*resultLength < lengthInWords * sizeof(uint32_t)) {
return PKA_STATUS_BUF_UNDERFLOW;
}
// Copy the resultant length.
*resultLength = lengthInWords * sizeof(uint32_t);
if (resultBuf) {
// Copy the result into the resultBuf.
for (i = 0; i < lengthInWords; i++) {
resultWordAlias[i]= HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
}
}
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Retrieve the result of a modulo operation or the remainder of a division.
//
//*****************************************************************************
static uint32_t PKAGetBigNumResultRemainder(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
{
uint32_t regMSWVal;
uint32_t lengthInWords;
uint32_t i;
uint32_t *resultWordAlias = (uint32_t *)resultBuf;
// Check the arguments.
ASSERT(resultBuf);
ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
(resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
// Verify that the operation is complete.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
// Get the MSW register value.
regMSWVal = HWREG(PKA_BASE + PKA_O_DIVMSW);
// If the result vector is zero, write back one zero byte so the caller does not need
// to handle a special error for the perhaps valid result of zero.
// They will only get the error status if they do not provide a buffer
if (regMSWVal & PKA_DIVMSW_RESULT_IS_ZERO_M) {
if (*resultLength){
if(resultBuf){
resultBuf[0] = 0;
}
*resultLength = 1;
return PKA_STATUS_SUCCESS;
}
else {
return PKA_STATUS_BUF_UNDERFLOW;
}
}
// Get the length of the result
lengthInWords = ((regMSWVal & PKA_DIVMSW_MSW_ADDRESS_M) + 1) - ((resultPKAMemAddr - PKA_RAM_BASE) >> 2);
// Check if the provided buffer length is adequate to store the result data.
if (*resultLength < lengthInWords * sizeof(uint32_t)) {
return PKA_STATUS_BUF_UNDERFLOW;
}
// Copy the resultant length.
*resultLength = lengthInWords * sizeof(uint32_t);
if (resultBuf) {
// Copy the result into the resultBuf.
for (i = 0; i < lengthInWords; i++) {
resultWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
}
}
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Writes the resultant curve point of an ECC operation to the provided buffer.
//
//*****************************************************************************
static uint32_t PKAGetECCResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
{
uint32_t i = 0;
uint32_t *xWordAlias = (uint32_t *)curvePointX;
uint32_t *yWordAlias = (uint32_t *)curvePointY;
uint32_t lengthInWordsCeiling = 0;
// Check for the arguments.
ASSERT(curvePointX);
ASSERT(curvePointY);
ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
(resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
// Verify that the operation is completed.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
if (HWREG(PKA_BASE + PKA_O_SHIFT)) {
return PKA_STATUS_FAILURE;
}
// Check to make sure that the result vector is not the point at infinity.
if (HWREG(PKA_BASE + PKA_O_MSW) & PKA_MSW_RESULT_IS_ZERO) {
return PKA_STATUS_POINT_AT_INFINITY;
}
if (curvePointX != NULL) {
// Copy the x co-ordinate value of the result from vector D into
// the curvePoint.
for (i = 0; i < (length / sizeof(uint32_t)); i++) {
xWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
}
// If the length is not a word-multiple, fill up a temporary word and copy that in
// to avoid a bus error.
if (length % sizeof(uint32_t)) {
uint32_t temp = 0;
uint8_t j;
// Load the entire word line of the coordinate remainder
temp = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
// Write all remaining bytes to the coordinate
for (j = 0; j < length % sizeof(uint32_t); j++) {
curvePointX[i * sizeof(uint32_t) + j] = ((uint8_t *)&temp)[j];
}
}
}
lengthInWordsCeiling = (length % sizeof(uint32_t)) ? length / sizeof(uint32_t) + 1 : length / sizeof(uint32_t);
resultPKAMemAddr += sizeof(uint32_t) * (2 + lengthInWordsCeiling + (lengthInWordsCeiling % 2));
if (curvePointY != NULL) {
// Copy the y co-ordinate value of the result from vector D into
// the curvePoint.
for (i = 0; i < (length / sizeof(uint32_t)); i++) {
yWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
}
// If the length is not a word-multiple, fill up a temporary word and copy that in
// to avoid a bus error.
if (length % sizeof(uint32_t)) {
uint32_t temp = 0;
uint8_t j;
// Load the entire word line of the coordinate remainder
temp = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
// Write all remaining bytes to the coordinate
for (j = 0; j < length % sizeof(uint32_t); j++) {
curvePointY[i * sizeof(uint32_t) + j] = ((uint8_t *)&temp)[j];
}
}
}
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Provides the PKA operation status.
//
//*****************************************************************************
uint32_t PKAGetOpsStatus(void)
{
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN_M) {
return PKA_STATUS_OPERATION_BUSY;
}
else {
return PKA_STATUS_OPERATION_RDY;
}
}
//*****************************************************************************
//
// Check if an array consists only of zeros.
//
//*****************************************************************************
bool PKAArrayAllZeros(const uint8_t *array, uint32_t arrayLength)
{
uint32_t i;
uint8_t arrayBits = 0;
// We could speed things up by comparing word-wise rather than byte-wise.
// However, this extra overhead is inconsequential compared to running an
// actual PKA operation. Especially ECC operations.
for (i = 0; i < arrayLength; i++) {
arrayBits |= array[i];
}
if (arrayBits) {
return false;
}
else {
return true;
}
}
//*****************************************************************************
//
// Fill an array with zeros
//
//*****************************************************************************
void PKAZeroOutArray(const uint8_t *array, uint32_t arrayLength)
{
uint32_t i;
// Take the floor of paramLength in 32-bit words
uint32_t arrayLengthInWords = arrayLength / sizeof(uint32_t);
// Zero-out the array word-wise until i >= arrayLength
for (i = 0; i < arrayLengthInWords * sizeof(uint32_t); i += 4) {
HWREG(array + i) = 0;
}
// If i != arrayLength, there are some remaining bytes to zero-out
if (arrayLength % sizeof(uint32_t)) {
// Subtract 4 from i, since i has already overshot the array
for (i -= 4; i < arrayLength; i++) {
HWREGB(array + i * sizeof(uint32_t));
}
}
}
//*****************************************************************************
//
// Start the big number modulus operation.
//
//*****************************************************************************
uint32_t PKABigNumModStart(const uint8_t *bigNum, uint32_t bigNumLength, const uint8_t *modulus, uint32_t modulusLength, uint32_t *resultPKAMemAddr)
{
uint32_t offset = 0;
// Check the arguments.
ASSERT(bigNum);
ASSERT(modulus);
ASSERT(resultPKAMemAddr);
// Make sure no operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(bigNum, bigNumLength, offset, PKA_O_APTR);
offset = PKAWritePkaParamExtraOffset(modulus, modulusLength, offset, PKA_O_BPTR);
// Copy the result vector address location.
*resultPKAMemAddr = PKA_RAM_BASE + offset;
// Load C pointer with the result location in PKA RAM
HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
// Start the PKCP modulo operation by setting the PKA Function register.
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MODULO);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the result of the big number modulus operation.
//
//*****************************************************************************
uint32_t PKABigNumModGetResult(uint8_t *resultBuf, uint32_t length, uint32_t resultPKAMemAddr)
{
// Zero-out array in case modulo result is shorter than length
PKAZeroOutArray(resultBuf, length);
return PKAGetBigNumResultRemainder(resultBuf, &length, resultPKAMemAddr);
}
//*****************************************************************************
//
// Start the big number divide operation.
//
//*****************************************************************************
uint32_t PKABigNumDivideStart(const uint8_t *dividend, uint32_t dividendLength, const uint8_t *divisor, uint32_t divisorLength, uint32_t *resultQuotientMemAddr, uint32_t *resultRemainderMemAddr)
{
uint32_t offset = 0;
// Check the arguments.
ASSERT(dividend);
ASSERT(divisor);
ASSERT(resultQuotientMemAddr);
ASSERT(resultRemainderMemAddr);
// Make sure no operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(dividend, dividendLength, offset, PKA_O_APTR);
offset = PKAWritePkaParamExtraOffset(divisor, divisorLength, offset, PKA_O_BPTR);
// Copy the remainder result vector address location.
if (resultRemainderMemAddr) {
*resultRemainderMemAddr = PKA_RAM_BASE + offset;
}
// The remainder cannot ever be larger than the divisor. It should fit inside
// a buffer of that size.
offset = PKAWritePkaParamExtraOffset(0, divisorLength, offset, PKA_O_CPTR);
// Copy the remainder result vector address location.
if (resultQuotientMemAddr) {
*resultQuotientMemAddr = PKA_RAM_BASE + offset;
}
// Load D pointer with the quotient location in PKA RAM
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
// Start the PKCP modulo operation by setting the PKA Function register.
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_DIVIDE);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the quotient of the big number divide operation.
//
//*****************************************************************************
uint32_t PKABigNumDivideGetQuotient(uint8_t *resultBuf, uint32_t *length, uint32_t resultQuotientMemAddr)
{
return PKAGetBigNumResult(resultBuf, length, resultQuotientMemAddr);
}
//*****************************************************************************
//
// Get the remainder of the big number divide operation.
//
//*****************************************************************************
uint32_t PKABigNumDivideGetRemainder(uint8_t *resultBuf, uint32_t *length, uint32_t resultQuotientMemAddr)
{
return PKAGetBigNumResultRemainder(resultBuf, length, resultQuotientMemAddr);
}
//*****************************************************************************
//
// Start the comparison of two big numbers.
//
//*****************************************************************************
uint32_t PKABigNumCmpStart(const uint8_t *bigNum1, const uint8_t *bigNum2, uint32_t length)
{
uint32_t offset = 0;
// Check the arguments.
ASSERT(bigNum1);
ASSERT(bigNum2);
// Make sure no operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(bigNum1, length, offset, PKA_O_APTR);
offset = PKAWritePkaParam(bigNum2, length, offset, PKA_O_BPTR);
// Set the PKA Function register for the Compare operation
// and start the operation.
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_COMPARE);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the result of the comparison operation of two big numbers.
//
//*****************************************************************************
uint32_t PKABigNumCmpGetResult(void)
{
uint32_t status;
// verify that the operation is complete.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
// Check the COMPARE register.
switch(HWREG(PKA_BASE + PKA_O_COMPARE)) {
case PKA_COMPARE_A_EQUALS_B:
status = PKA_STATUS_EQUAL;
break;
case PKA_COMPARE_A_GREATER_THAN_B:
status = PKA_STATUS_A_GREATER_THAN_B;
break;
case PKA_COMPARE_A_LESS_THAN_B:
status = PKA_STATUS_A_LESS_THAN_B;
break;
default:
status = PKA_STATUS_FAILURE;
break;
}
return status;
}
//*****************************************************************************
//
// Start the big number inverse modulo operation.
//
//*****************************************************************************
uint32_t PKABigNumInvModStart(const uint8_t *bigNum, uint32_t bigNumLength, const uint8_t *modulus, uint32_t modulusLength, uint32_t *resultPKAMemAddr)
{
uint32_t offset = 0;
// Check the arguments.
ASSERT(bigNum);
ASSERT(modulus);
ASSERT(resultPKAMemAddr);
// Make sure no operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(bigNum, bigNumLength, offset, PKA_O_APTR);
offset = PKAWritePkaParam(modulus, modulusLength, offset, PKA_O_BPTR);
// Copy the result vector address location.
*resultPKAMemAddr = PKA_RAM_BASE + offset;
// Load D pointer with the result location in PKA RAM.
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
// set the PKA function to InvMod operation and the start the operation.
HWREG(PKA_BASE + PKA_O_FUNCTION) = 0x0000F000;
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the result of the big number inverse modulo operation.
//
//*****************************************************************************
uint32_t PKABigNumInvModGetResult(uint8_t *resultBuf, uint32_t length, uint32_t resultPKAMemAddr)
{
// Zero-out array in case modulo result is shorter than length
PKAZeroOutArray(resultBuf, length);
return PKAGetBigNumResult(resultBuf, &length, resultPKAMemAddr);
}
//*****************************************************************************
//
// Start the big number multiplication.
//
//*****************************************************************************
uint32_t PKABigNumMultiplyStart(const uint8_t *multiplicand, uint32_t multiplicandLength, const uint8_t *multiplier, uint32_t multiplierLength, uint32_t *resultPKAMemAddr)
{
uint32_t offset = 0;
// Check for the arguments.
ASSERT(multiplicand);
ASSERT(multiplier);
ASSERT(resultPKAMemAddr);
// Make sure no operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(multiplicand, multiplicandLength, offset, PKA_O_APTR);
offset = PKAWritePkaParam(multiplier, multiplierLength, offset, PKA_O_BPTR);
// Copy the result vector address location.
*resultPKAMemAddr = PKA_RAM_BASE + offset;
// Load C pointer with the result location in PKA RAM.
HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
// Set the PKA function to the multiplication and start it.
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MULTIPLY);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the results of the big number multiplication.
//
//*****************************************************************************
uint32_t PKABigNumMultGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
{
return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
}
//*****************************************************************************
//
// Start the addition of two big number.
//
//*****************************************************************************
uint32_t PKABigNumAddStart(const uint8_t *bigNum1, uint32_t bigNum1Length, const uint8_t *bigNum2, uint32_t bigNum2Length, uint32_t *resultPKAMemAddr)
{
uint32_t offset = 0;
// Check for arguments.
ASSERT(bigNum1);
ASSERT(bigNum2);
ASSERT(resultPKAMemAddr);
// Make sure no operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(bigNum1, bigNum1Length, offset, PKA_O_APTR);
offset = PKAWritePkaParam(bigNum2, bigNum2Length, offset, PKA_O_BPTR);
// Copy the result vector address location.
*resultPKAMemAddr = PKA_RAM_BASE + offset;
// Load C pointer with the result location in PKA RAM.
HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
// Set the function for the add operation and start the operation.
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_ADD);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the result of the addition operation on two big number.
//
//*****************************************************************************
uint32_t PKABigNumSubGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
{
return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
}
//*****************************************************************************
//
// Start the addition of two big number.
//
//*****************************************************************************
uint32_t PKABigNumSubStart(const uint8_t *minuend, uint32_t minuendLength, const uint8_t *subtrahend, uint32_t subtrahendLength, uint32_t *resultPKAMemAddr)
{
uint32_t offset = 0;
// Check for arguments.
ASSERT(minuend);
ASSERT(subtrahend);
ASSERT(resultPKAMemAddr);
// Make sure no operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(minuend, minuendLength, offset, PKA_O_APTR);
offset = PKAWritePkaParam(subtrahend, subtrahendLength, offset, PKA_O_BPTR);
// Copy the result vector address location.
*resultPKAMemAddr = PKA_RAM_BASE + offset;
// Load C pointer with the result location in PKA RAM.
HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
// Set the function for the add operation and start the operation.
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_SUBTRACT);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the result of the addition operation on two big number.
//
//*****************************************************************************
uint32_t PKABigNumAddGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
{
return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
}
//*****************************************************************************
//
// Start ECC Multiplication.
//
//*****************************************************************************
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)
{
uint32_t offset = 0;
// Check for the arguments.
ASSERT(scalar);
ASSERT(curvePointX);
ASSERT(curvePointY);
ASSERT(prime);
ASSERT(a);
ASSERT(b);
ASSERT(length <= PKA_MAX_CURVE_SIZE_32_BIT_WORD * sizeof(uint32_t));
ASSERT(resultPKAMemAddr);
// Make sure no PKA operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(scalar, length, offset, PKA_O_APTR);
offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
offset = PKAWritePkaParamExtraOffset(b, length, offset, PKA_NO_POINTER_REG);
offset = PKAWritePkaParamExtraOffset(curvePointX, length, offset, PKA_O_CPTR);
offset = PKAWritePkaParamExtraOffset(curvePointY, length, offset, PKA_NO_POINTER_REG);
// Update the result location.
// The resultPKAMemAddr may be 0 if we only want to check that we generated the point at infinity
if (resultPKAMemAddr) {
*resultPKAMemAddr = PKA_RAM_BASE + offset;
}
// Load D pointer with the result location in PKA RAM.
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
// Set the PKA function to ECC-MULT and start the operation.
HWREG(PKA_BASE + PKA_O_FUNCTION) = PKA_FUNCTION_RUN_M | (0x05 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Start ECC Montgomery Multiplication.
//
//*****************************************************************************
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)
{
uint32_t offset = 0;
// Check for the arguments.
ASSERT(scalar);
ASSERT(curvePointX);
ASSERT(prime);
ASSERT(a);
ASSERT(length <= PKA_MAX_CURVE_SIZE_32_BIT_WORD * sizeof(uint32_t));
ASSERT(resultPKAMemAddr);
// Make sure no PKA operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParam(scalar, length, offset, PKA_O_APTR);
offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
offset = PKAWritePkaParamExtraOffset(curvePointX, length, offset, PKA_O_CPTR);
// Update the result location.
// The resultPKAMemAddr may be 0 if we only want to check that we generated the point at infinity
if (resultPKAMemAddr) {
*resultPKAMemAddr = PKA_RAM_BASE + offset;
}
// Load D pointer with the result location in PKA RAM.
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
// Set the PKA function to Montgomery ECC-MULT and start the operation.
HWREG(PKA_BASE + PKA_O_FUNCTION) = PKA_FUNCTION_RUN_M | (0x02 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the result of ECC Multiplication
//
//*****************************************************************************
uint32_t PKAEccMultiplyGetResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
{
return PKAGetECCResult(curvePointX, curvePointY, resultPKAMemAddr, length);
}
//*****************************************************************************
//
// Start the ECC Addition.
//
//*****************************************************************************
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)
{
uint32_t offset = 0;
// Check for the arguments.
ASSERT(curvePoint1X);
ASSERT(curvePoint1Y);
ASSERT(curvePoint2X);
ASSERT(curvePoint2Y);
ASSERT(prime);
ASSERT(a);
ASSERT(resultPKAMemAddr);
// Make sure no operation is in progress.
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
return PKA_STATUS_OPERATION_BUSY;
}
offset = PKAWritePkaParamExtraOffset(curvePoint1X, length, offset, PKA_O_APTR);
offset = PKAWritePkaParamExtraOffset(curvePoint1Y, length, offset, PKA_NO_POINTER_REG);
offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
offset = PKAWritePkaParamExtraOffset(curvePoint2X, length, offset, PKA_O_CPTR);
offset = PKAWritePkaParamExtraOffset(curvePoint2Y, length, offset, PKA_NO_POINTER_REG);
// Copy the result vector location.
*resultPKAMemAddr = PKA_RAM_BASE + offset;
// Load D pointer with the result location in PKA RAM.
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
// Set the PKA Function to ECC-ADD and start the operation.
HWREG(PKA_BASE + PKA_O_FUNCTION ) = PKA_FUNCTION_RUN_M | (0x03 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
return PKA_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Get the result of the ECC Addition
//
//*****************************************************************************
uint32_t PKAEccAddGetResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
{
return PKAGetECCResult(curvePointX, curvePointY, resultPKAMemAddr, length);
}
//*****************************************************************************
//
// Verify a public key against the supplied elliptic curve equation
//
//*****************************************************************************
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)
{
uint32_t pkaResult;
uint32_t resultAddress;
uint32_t resultLength;
uint8_t *scratchBuffer = (uint8_t *)(PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE / 2);
uint8_t *scratchBuffer2 = scratchBuffer + 512;
// Verify X in range [0, prime - 1]
PKABigNumCmpStart(curvePointX,
prime,
length);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
pkaResult = PKABigNumCmpGetResult();
if (pkaResult != PKA_STATUS_A_LESS_THAN_B) {
return PKA_STATUS_X_LARGER_THAN_PRIME;
}
// Verify Y in range [0, prime - 1]
PKABigNumCmpStart(curvePointY,
prime,
length);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
pkaResult = PKABigNumCmpGetResult();
if (pkaResult != PKA_STATUS_A_LESS_THAN_B) {
return PKA_STATUS_Y_LARGER_THAN_PRIME;
}
// Verify point on curve
// Short-Weierstrass equation: Y ^ 2 = X ^3 + a * X + b mod P
// Reduced: Y ^ 2 = X * (X ^ 2 + a) + b
// tmp = X ^ 2
PKABigNumMultiplyStart(curvePointX, length, curvePointX, length, &resultAddress);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
resultLength = 200;
pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
if (pkaResult != PKA_STATUS_SUCCESS) {
return PKA_STATUS_FAILURE;
}
// tmp += a
PKABigNumAddStart(scratchBuffer, resultLength, a, length, &resultAddress);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
resultLength = 200;
pkaResult = PKABigNumAddGetResult(scratchBuffer, &resultLength, resultAddress);
if (pkaResult != PKA_STATUS_SUCCESS) {
return PKA_STATUS_FAILURE;
}
// tmp *= x
PKABigNumMultiplyStart(scratchBuffer, resultLength, curvePointX, length, &resultAddress);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
resultLength = 200;
pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
if (pkaResult != PKA_STATUS_SUCCESS) {
return PKA_STATUS_FAILURE;
}
// tmp += b
PKABigNumAddStart(scratchBuffer, resultLength, b, length, &resultAddress);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
resultLength = 200;
pkaResult = PKABigNumAddGetResult(scratchBuffer, &resultLength, resultAddress);
if (pkaResult != PKA_STATUS_SUCCESS) {
return PKA_STATUS_FAILURE;
}
// tmp2 = tmp % prime to ensure we have no fraction in the division.
// The number will only shrink from here on out.
PKABigNumModStart(scratchBuffer, resultLength, prime, length, &resultAddress);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
// If the result is not a multiple of the word-length, the PKA HW will round up
// because it deals in words only. That means that using 'length' directly
// would cause and underflow, since length refers to the actual length in bytes of
// the curve parameters while the PKA HW reports that rounded up to the next
// word boundary.
// Use 200 as the resultLength instead since we are copying to the scratch buffer
// anyway.
// Practically, this only happens with curves such as NIST-P521 that are not word
// multiples.
resultLength = 200;
pkaResult = PKABigNumModGetResult(scratchBuffer2, resultLength, resultAddress);
if (pkaResult != PKA_STATUS_SUCCESS) {
return PKA_STATUS_FAILURE;
}
// tmp = y^2
PKABigNumMultiplyStart(curvePointY, length, curvePointY, length, &resultAddress);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
resultLength = 200;
pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
if (pkaResult != PKA_STATUS_SUCCESS) {
return PKA_STATUS_FAILURE;
}
// tmp %= prime
PKABigNumModStart(scratchBuffer, resultLength, prime, length, &resultAddress);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
// If the result is not a multiple of the word-length, the PKA HW will round up
// because it deals in words only. That means that using 'length' directly
// would cause and underflow, since length refers to the actual length in bytes of
// the curve parameters while the PKA HW reports that rounded up to the next
// word boundary.
// Use 200 as the resultLength instead since we are copying to the scratch buffer
// anyway.
// Practically, this only happens with curves such as NIST-P521 that are not word
// multiples.
resultLength = 200;
pkaResult = PKABigNumModGetResult(scratchBuffer, resultLength, resultAddress);
if (pkaResult != PKA_STATUS_SUCCESS) {
return PKA_STATUS_FAILURE;
}
// tmp ?= tmp2
PKABigNumCmpStart(scratchBuffer,
scratchBuffer2,
length);
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
pkaResult = PKABigNumCmpGetResult();
if (pkaResult != PKA_STATUS_EQUAL) {
return PKA_STATUS_POINT_NOT_ON_CURVE;
}
else {
return PKA_STATUS_SUCCESS;
}
}