/* * Original file: * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * All rights reserved. * * Port to Contiki: * Authors: Andreas Dröscher * Hu Luo * Hossein Shafagh * * 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 copyright holder 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. */ /** * \addtogroup cc2538-bignum * @{ * * \file * Implementation of the cc2538 BigNum driver * * bignum_subtract_start bignum_subtract_get_result (subtraction) * bignum_add_start bignum_add_get_result (addition) * bignum_mod_start bignum_mod_get_result (modulo) * bignum_exp_mod_start bignum_exp_mod_get_result (modular exponentiation operation) * bignum_inv_mod_start bignum_inv_mod_get_result (inverse modulo operation) * bignum_mul_start bignum_mul_get_result (multiplication) * bignum_divide_start bignum_divide_get_result (division) * bignum_cmp_start bignum_cmp_get_result (comparison) */ #include "dev/bignum-driver.h" #include #include "reg.h" #include "dev/nvic.h" #define ASSERT(IF) if(!(IF)) { return PKA_STATUS_INVALID_PARAM; } /*---------------------------------------------------------------------------*/ uint8_t bignum_mod_start(const uint32_t *number, const uint8_t number_size, const uint32_t *modulus, const uint8_t modulus_size, uint32_t *result_vector, struct process *process) { uint8_t extraBuf; uint32_t offset; int i; /* Check the arguments. */ ASSERT(NULL != number); ASSERT(NULL != modulus); ASSERT(NULL != result_vector); /* make sure no operation is in progress. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* calculate the extra buffer requirement. */ extraBuf = 2 + modulus_size % 2; offset = 0; /* Update the A ptr with the offset address of the PKA RAM location * where the number will be stored. */ REG(PKA_APTR) = offset >> 2; /* Load the number in PKA RAM */ for(i = 0; i < number_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number[i]; } /* determine the offset for the next data input. */ offset += 4 * (i + number_size % 2); /* Update the B ptr with the offset address of the PKA RAM location * where the divisor will be stored. */ REG(PKA_BPTR) = offset >> 2; /* Load the divisor in PKA RAM. */ for(i = 0; i < modulus_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = modulus[i]; } /* determine the offset for the next data. */ offset += 4 * (i + extraBuf); /* Copy the result vector address location. */ *result_vector = PKA_RAM_BASE + offset; /* Load C ptr with the result location in PKA RAM */ REG(PKA_CPTR) = offset >> 2; /* Load A length registers with Big number length in 32 bit words. */ REG(PKA_ALENGTH) = number_size; /* Load B length registers Divisor length in 32-bit words. */ REG(PKA_BLENGTH) = modulus_size; /* Start the PKCP modulo operation by setting the PKA Function register. */ REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MODULO); /* Enable Interrupt */ if(process != NULL) { pka_register_process_notification(process); NVIC_ClearPendingIRQ(PKA_IRQn); NVIC_EnableIRQ(PKA_IRQn); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_mod_get_result(uint32_t *buffer, const uint8_t buffer_size, const uint32_t result_vector) { uint32_t regMSWVal; uint32_t len; int i; /* Check the arguments. */ ASSERT(NULL != buffer); ASSERT(result_vector > PKA_RAM_BASE); ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); /* verify that the operation is complete. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Disable Interrupt */ NVIC_DisableIRQ(PKA_IRQn); pka_register_process_notification(NULL); /* Get the MSW register value. */ regMSWVal = REG(PKA_DIVMSW); /* Check to make sure that the result vector is not all zeroes. */ if(regMSWVal & PKA_DIVMSW_RESULT_IS_ZERO) { return PKA_STATUS_RESULT_0; } /* Get the length of the result. */ len = ((regMSWVal & PKA_DIVMSW_MSW_ADDRESS_M) + 1) - ((result_vector - PKA_RAM_BASE) >> 2); /* If the size of the buffer provided is less than the result length than * return error. */ if(buffer_size < len) { return PKA_STATUS_BUF_UNDERFLOW; } /* copy the result from vector C into the pResult. */ for(i = 0; i < len; i++) { buffer[i] = REG(result_vector + 4 * i); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_cmp_start(const uint32_t *number1, const uint32_t *number2, const uint8_t size, struct process *process) { uint32_t offset; int i; /* Check the arguments. */ ASSERT(NULL != number1); ASSERT(NULL != number2); offset = 0; /* Make sure no operation is in progress. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Update the A ptr with the offset address of the PKA RAM location * where the first big number will be stored. */ REG(PKA_APTR) = offset >> 2; /* Load the first big number in PKA RAM. */ for(i = 0; i < size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number1[i]; } /* Determine the offset in PKA RAM for the next pointer. */ offset += 4 * (i + size % 2); /* Update the B ptr with the offset address of the PKA RAM location * where the second big number will be stored. */ REG(PKA_BPTR) = offset >> 2; /* Load the second big number in PKA RAM. */ for(i = 0; i < size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number2[i]; } /* Load length registers in 32 bit word size. */ REG(PKA_ALENGTH) = size; /* Set the PKA Function register for the compare operation * and start the operation. */ REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_COMPARE); /* Enable Interrupt */ if(process != NULL) { pka_register_process_notification(process); NVIC_ClearPendingIRQ(PKA_IRQn); NVIC_EnableIRQ(PKA_IRQn); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_cmp_get_result(void) { uint8_t status; /* verify that the operation is complete. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { status = PKA_STATUS_OPERATION_INPRG; return status; } /* Disable Interrupt */ NVIC_DisableIRQ(PKA_IRQn); pka_register_process_notification(NULL); /* Check the compare register. */ switch(REG(PKA_COMPARE)) { case PKA_COMPARE_A_EQUALS_B: status = PKA_STATUS_SUCCESS; break; case PKA_COMPARE_A_GREATER_THAN_B: status = PKA_STATUS_A_GR_B; break; case PKA_COMPARE_A_LESS_THAN_B: status = PKA_STATUS_A_LT_B; break; default: status = PKA_STATUS_FAILURE; break; } return status; } /*---------------------------------------------------------------------------*/ uint8_t bignum_inv_mod_start(const uint32_t *number, const uint8_t number_size, const uint32_t *modulus, const uint8_t modulus_size, uint32_t *result_vector, struct process *process) { uint32_t offset; int i; /* Check the arguments. */ ASSERT(NULL != number); ASSERT(NULL != modulus); ASSERT(NULL != result_vector); offset = 0; /* Make sure no operation is in progress. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Update the A ptr with the offset address of the PKA RAM location * where the number will be stored. */ REG(PKA_APTR) = offset >> 2; /* Load the \e number number in PKA RAM. */ for(i = 0; i < number_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number[i]; } /* Determine the offset for next data. */ offset += 4 * (i + number_size % 2); /* Update the B ptr with the offset address of the PKA RAM location * where the modulus will be stored. */ REG(PKA_BPTR) = offset >> 2; /* Load the \e modulus divisor in PKA RAM. */ for(i = 0; i < modulus_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = modulus[i]; } /* Determine the offset for result data. */ offset += 4 * (i + modulus_size % 2); /* Copy the result vector address location. */ *result_vector = PKA_RAM_BASE + offset; /* Load D ptr with the result location in PKA RAM. */ REG(PKA_DPTR) = offset >> 2; /* Load the respective length registers. */ REG(PKA_ALENGTH) = number_size; REG(PKA_BLENGTH) = modulus_size; /* set the PKA function to InvMod operation and the start the operation. */ REG(PKA_FUNCTION) = 0x0000F000; /* Enable Interrupt */ if(process != NULL) { pka_register_process_notification(process); NVIC_ClearPendingIRQ(PKA_IRQn); NVIC_EnableIRQ(PKA_IRQn); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_inv_mod_get_result(uint32_t *buffer, const uint8_t buffer_size, const uint32_t result_vector) { uint32_t regMSWVal; uint32_t len; int i; /* Check the arguments. */ ASSERT(NULL != buffer); ASSERT(result_vector > PKA_RAM_BASE); ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); /* Verify that the operation is complete. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Disable Interrupt */ NVIC_DisableIRQ(PKA_IRQn); pka_register_process_notification(NULL); /* Get the MSW register value. */ regMSWVal = REG(PKA_MSW); /* Check to make sure that the result vector is not all zeroes. */ if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { return PKA_STATUS_RESULT_0; } /* Get the length of the result */ len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) - ((result_vector - PKA_RAM_BASE) >> 2); /* Check if the provided buffer length is adequate to store the result * data. */ if(buffer_size < len) { return PKA_STATUS_BUF_UNDERFLOW; } /* Copy the result from vector C into the \e buffer. */ for(i = 0; i < len; i++) { buffer[i] = REG(result_vector + 4 * i); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_mul_start(const uint32_t *multiplicand, const uint8_t multiplicand_size, const uint32_t *multiplier, const uint8_t multiplier_size, uint32_t *result_vector, struct process *process) { uint32_t offset; int i; /* Check for the arguments. */ ASSERT(NULL != multiplicand); ASSERT(NULL != multiplier); ASSERT(NULL != result_vector); offset = 0; /* Make sure no operation is in progress. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Update the A ptr with the offset address of the PKA RAM location * where the multiplicand will be stored. */ REG(PKA_APTR) = offset >> 2; /* Load the multiplicand in PKA RAM. */ for(i = 0; i < multiplicand_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = *multiplicand; multiplicand++; } /* Determine the offset for the next data. */ offset += 4 * (i + (multiplicand_size % 2)); /* Update the B ptr with the offset address of the PKA RAM location * where the multiplier will be stored. */ REG(PKA_BPTR) = offset >> 2; /* Load the multiplier in PKA RAM. */ for(i = 0; i < multiplier_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = *multiplier; multiplier++; } /* Determine the offset for the next data. */ offset += 4 * (i + (multiplier_size % 2)); /* Copy the result vector address location. */ *result_vector = PKA_RAM_BASE + offset; /* Load C ptr with the result location in PKA RAM. */ REG(PKA_CPTR) = offset >> 2; /* Load the respective length registers. */ REG(PKA_ALENGTH) = multiplicand_size; REG(PKA_BLENGTH) = multiplier_size; /* Set the PKA function to the multiplication and start it. */ REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MULTIPLY); /* Enable Interrupt */ if(process != NULL) { pka_register_process_notification(process); NVIC_ClearPendingIRQ(PKA_IRQn); NVIC_EnableIRQ(PKA_IRQn); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_mul_get_result(uint32_t *buffer, uint32_t *buffer_size, const uint32_t result_vector) { uint32_t regMSWVal; uint32_t len; int i; /* Check for arguments. */ ASSERT(NULL != buffer); ASSERT(NULL != buffer_size); ASSERT(result_vector > PKA_RAM_BASE); ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); /* Verify that the operation is complete. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Disable Interrupt */ NVIC_DisableIRQ(PKA_IRQn); pka_register_process_notification(NULL); /* Get the MSW register value. */ regMSWVal = REG(PKA_MSW); /* Check to make sure that the result vector is not all zeroes. */ if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { return PKA_STATUS_RESULT_0; } /* Get the length of the result. */ len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) - ((result_vector - PKA_RAM_BASE) >> 2); /* Make sure that the length of the supplied result buffer is adequate * to store the resultant. */ if(*buffer_size < len) { return PKA_STATUS_BUF_UNDERFLOW; } /* Copy the resultant length. */ *buffer_size = len; /* Copy the result from vector C into the pResult. */ for(i = 0; i < *buffer_size; i++) { buffer[i] = REG(result_vector + 4 * i); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_add_start(const uint32_t *number1, const uint8_t number1_size, const uint32_t *number2, const uint8_t number2_size, uint32_t *result_vector, struct process *process) { uint32_t offset; int i; /* Check for arguments. */ ASSERT(NULL != number1); ASSERT(NULL != number2); ASSERT(NULL != result_vector); offset = 0; /* Make sure no operation is in progress. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Update the A ptr with the offset address of the PKA RAM location * where the big number 1 will be stored. */ REG(PKA_APTR) = offset >> 2; /* Load the big number 1 in PKA RAM. */ for(i = 0; i < number1_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number1[i]; } /* Determine the offset in PKA RAM for the next data. */ offset += 4 * (i + (number1_size % 2)); /* Update the B ptr with the offset address of the PKA RAM location * where the big number 2 will be stored. */ REG(PKA_BPTR) = offset >> 2; /* Load the big number 2 in PKA RAM. */ for(i = 0; i < number2_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number2[i]; } /* Determine the offset in PKA RAM for the next data. */ offset += 4 * (i + (number2_size % 2)); /* Copy the result vector address location. */ *result_vector = PKA_RAM_BASE + offset; /* Load C ptr with the result location in PKA RAM. */ REG(PKA_CPTR) = offset >> 2; /* Load respective length registers. */ REG(PKA_ALENGTH) = number1_size; REG(PKA_BLENGTH) = number2_size; /* Set the function for the add operation and start the operation. */ REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_ADD); /* Enable Interrupt */ if(process != NULL) { pka_register_process_notification(process); NVIC_ClearPendingIRQ(PKA_IRQn); NVIC_EnableIRQ(PKA_IRQn); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_add_get_result(uint32_t *buffer, uint32_t *buffer_size, const uint32_t result_vector) { uint32_t regMSWVal; uint32_t len; int i; /* Check for the arguments. */ ASSERT(NULL != buffer); ASSERT(NULL != buffer_size); ASSERT(result_vector > PKA_RAM_BASE); ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); /* Verify that the operation is complete. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Disable Interrupt */ NVIC_DisableIRQ(PKA_IRQn); pka_register_process_notification(NULL); /* Get the MSW register value. */ regMSWVal = REG(PKA_MSW); /* Check to make sure that the result vector is not all zeroes. */ if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { return PKA_STATUS_RESULT_0; } /* Get the length of the result. */ len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) - ((result_vector - PKA_RAM_BASE) >> 2); /* Make sure that the supplied result buffer is adequate to store the * resultant data. */ if(*buffer_size < len) { return PKA_STATUS_BUF_UNDERFLOW; } /* Copy the length. */ *buffer_size = len; /* Copy the result from vector C into the provided buffer. */ for(i = 0; i < *buffer_size; i++) { buffer[i] = REG(result_vector + 4 * i); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ /* below functions are added by hu luo */ uint8_t bignum_subtract_start(const uint32_t *number1, const uint8_t number1_size, const uint32_t *number2, const uint8_t number2_size, uint32_t *result_vector, struct process *process) { uint32_t offset; int i; /* Check for arguments. */ ASSERT(NULL != number1); ASSERT(NULL != number2); ASSERT(NULL != result_vector); offset = 0; /* Make sure no operation is in progress. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Update the A ptr with the offset address of the PKA RAM location * where the big number 1 will be stored. */ REG(PKA_APTR) = offset >> 2; /* Load the big number 1 in PKA RAM. */ for(i = 0; i < number1_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number1[i]; } /* Determine the offset in PKA RAM for the next data. */ offset += 4 * (i + (number1_size % 2)); /* Update the B ptr with the offset address of the PKA RAM location * where the big number 2 will be stored. */ REG(PKA_BPTR) = offset >> 2; /* Load the big number 2 in PKA RAM. */ for(i = 0; i < number2_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number2[i]; } /* Determine the offset in PKA RAM for the next data. */ offset += 4 * (i + (number2_size % 2)); /* Copy the result vector address location. */ *result_vector = PKA_RAM_BASE + offset; /* Load C ptr with the result location in PKA RAM. */ REG(PKA_CPTR) = offset >> 2; /* Load respective length registers. */ REG(PKA_ALENGTH) = number1_size; REG(PKA_BLENGTH) = number2_size; /* Set the function for the add operation and start the operation. */ REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_SUBTRACT); /* Enable Interrupt */ if(process != NULL) { pka_register_process_notification(process); NVIC_ClearPendingIRQ(PKA_IRQn); NVIC_EnableIRQ(PKA_IRQn); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_subtract_get_result(uint32_t *buffer, uint32_t *buffer_size, const uint32_t result_vector) { uint32_t regMSWVal; uint32_t len; int i; /* Check for the arguments. */ ASSERT(NULL != buffer); ASSERT(NULL != buffer_size); ASSERT(result_vector > PKA_RAM_BASE); ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); /* Verify that the operation is complete. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Disable Interrupt */ NVIC_DisableIRQ(PKA_IRQn); pka_register_process_notification(NULL); /* Get the MSW register value. */ regMSWVal = REG(PKA_MSW); /* Check to make sure that the result vector is not all zeroes. */ if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { return PKA_STATUS_RESULT_0; } /* Get the length of the result. */ len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) - ((result_vector - PKA_RAM_BASE) >> 2); /* Make sure that the supplied result buffer is adequate to store the * resultant data. */ if(*buffer_size < len) { return PKA_STATUS_BUF_UNDERFLOW; } /* Copy the length. */ *buffer_size = len; /* Copy the result from vector C into the provided buffer. */ for(i = 0; i < *buffer_size; i++) { buffer[i] = REG(result_vector + 4 * i); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_exp_mod_start(const uint32_t *number, const uint8_t number_size, const uint32_t *modulus, const uint8_t modulus_size, const uint32_t *base, const uint8_t base_size, uint32_t *result_vector, struct process *process) { uint32_t offset; int i; /* Check for the arguments. */ ASSERT(NULL != number); ASSERT(NULL != modulus); ASSERT(NULL != base); ASSERT(NULL != result_vector); ASSERT(modulus != base); offset = 0; /* Make sure no PKA operation is in progress. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Update the A ptr with the offset address of the PKA RAM location * where the exponent will be stored. */ REG(PKA_APTR) = offset >> 2; /* Load the Exponent in PKA RAM. */ for(i = 0; i < number_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = number[i]; } /* Determine the offset for the next data(BPTR). */ offset += 4 * (i + number_size % 2); /* Update the B ptr with the offset address of the PKA RAM location * where the divisor will be stored. */ REG(PKA_BPTR) = offset >> 2; /* Load the Modulus in PKA RAM. */ for(i = 0; i < modulus_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = modulus[i]; } /* Determine the offset for the next data(CPTR). */ offset += 4 * (i + modulus_size % 2 + 2); /* Update the C ptr with the offset address of the PKA RAM location * where the Base will be stored. */ REG(PKA_CPTR) = offset >> 2; /* Write Base to the Vector C in PKA RAM */ for(i = 0; i < base_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = base[i]; } /* Determine the offset for the next data. * INFO D and B can share the same memory area! * offset += 4 * (i + extraBuf + 2); */ /* Copy the result vector address location. */ *result_vector = PKA_RAM_BASE + offset; /* Load D ptr with the result location in PKA RAM */ REG(PKA_DPTR) = offset >> 2; /* Load A length registers with Big number length in 32 bit words. */ REG(PKA_ALENGTH) = number_size; /* Load B length registers Divisor length in 32-bit words. */ REG(PKA_BLENGTH) = modulus_size; /* REG(PKA_SHIFT) = 0x00000001; * Required for (EXPMod-variable): 0x0000A000 * Start the PKCP modulo exponentiation operation(EXPMod-ACT2) * by setting the PKA Function register. */ REG(PKA_FUNCTION) = 0x0000C000; /* Enable Interrupt */ if(process != NULL) { pka_register_process_notification(process); NVIC_ClearPendingIRQ(PKA_IRQn); NVIC_EnableIRQ(PKA_IRQn); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_exp_mod_get_result(uint32_t *buffer, const uint8_t buffer_size, const uint32_t result_vector) { uint32_t regMSWVal; uint32_t len; int i; /* Check the arguments. */ ASSERT(NULL != buffer); ASSERT(result_vector > PKA_RAM_BASE); ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); /* verify that the operation is complete. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Disable Interrupt */ NVIC_DisableIRQ(PKA_IRQn); pka_register_process_notification(NULL); /* Get the MSW register value. */ regMSWVal = REG(PKA_MSW); /* Check to make sure that the result vector is not all zeroes. */ if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { return PKA_STATUS_RESULT_0; } /* Get the length of the result */ len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) - ((result_vector - PKA_RAM_BASE) >> 2); /* If the size of the buffer provided is less than the result length than * return error. */ if(buffer_size < len) { return PKA_STATUS_BUF_UNDERFLOW; } /* copy the result from vector C into the pResult. */ for(i = 0; i < len; i++) { buffer[i] = REG(result_vector + 4 * i); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_divide_start(const uint32_t *dividend, const uint8_t dividend_size, const uint32_t *divisor, const uint8_t divisor_size, uint32_t *result_vector, struct process *process) { uint32_t offset; uint32_t spacing; int i; /* We use largest len for spacing */ if(dividend_size > divisor_size) { spacing = dividend_size; } else { spacing = divisor_size; } spacing += 2 + spacing % 2; /* Check for the arguments. */ ASSERT(NULL != dividend); ASSERT(NULL != divisor); ASSERT(NULL != result_vector); /* Make sure no operation is in progress. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Update the A ptr with the offset address of the PKA RAM location * where the multiplicand will be stored. */ offset = 0; REG(PKA_APTR) = offset >> 2; /* Load the multiplicand in PKA RAM. */ for(i = 0; i < dividend_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = *dividend; dividend++; } /* Determine the offset for the next data. */ offset += 4 * spacing; /* Update the B ptr with the offset address of the PKA RAM location * where the multiplier will be stored. */ REG(PKA_BPTR) = offset >> 2; /* Load the multiplier in PKA RAM. */ for(i = 0; i < divisor_size; i++) { REG(PKA_RAM_BASE + offset + 4 * i) = *divisor; divisor++; } /* Determine the offset for the reminder. */ offset += 4 * spacing; /* Load C ptr with the result location in PKA RAM. */ REG(PKA_CPTR) = offset >> 2; /* Determine the offset for the quotient. */ offset += 4 * spacing; /* Copy the quotient vector address location. */ *result_vector = PKA_RAM_BASE + offset; /* Load D ptr with the result location in PKA RAM. */ REG(PKA_DPTR) = offset >> 2; /* Load the respective length registers. */ REG(PKA_ALENGTH) = dividend_size; REG(PKA_BLENGTH) = divisor_size; /* Set the PKA function to the multiplication and start it. */ REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_DIVIDE); /* Enable Interrupt */ if(process != NULL) { pka_register_process_notification(process); NVIC_ClearPendingIRQ(PKA_IRQn); NVIC_EnableIRQ(PKA_IRQn); } return PKA_STATUS_SUCCESS; } /*---------------------------------------------------------------------------*/ uint8_t bignum_divide_get_result(uint32_t *buffer, uint32_t *buffer_size, const uint32_t result_vector) { uint32_t regMSWVal; uint32_t len; int i; /* Check for arguments. */ ASSERT(NULL != buffer); ASSERT(NULL != buffer_size); ASSERT(result_vector > PKA_RAM_BASE); ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); /* Verify that the operation is complete. */ if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { return PKA_STATUS_OPERATION_INPRG; } /* Disable Interrupt */ NVIC_DisableIRQ(PKA_IRQn); pka_register_process_notification(NULL); /* Get the MSW register value. */ regMSWVal = REG(PKA_MSW); /* Check to make sure that the result vector is not all zeroes. */ if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { return PKA_STATUS_RESULT_0; } /* Get the length of the result. */ len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) - ((result_vector - PKA_RAM_BASE) >> 2); /* Make sure that the length of the supplied result buffer is adequate * to store the resultant. */ if(*buffer_size < len) { return PKA_STATUS_BUF_UNDERFLOW; } /* Copy the resultant length. */ *buffer_size = len; /* Copy the result from vector C into the pResult. */ for(i = 0; i < *buffer_size; i++) { buffer[i] = REG(result_vector + 4 * i); } return PKA_STATUS_SUCCESS; } /** @} */