Webserver+3d print

Dependents:   Nucleo

Revision:
0:8918a71cdbe9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyclone_crypto/ec_curves.c	Sat Feb 04 18:15:49 2017 +0000
@@ -0,0 +1,1958 @@
+/**
+ * @file ec_curves.c
+ * @brief Elliptic curves
+ *
+ * @section License
+ *
+ * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
+ *
+ * This file is part of CycloneCrypto Open.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * @author Oryx Embedded SARL (www.oryx-embedded.com)
+ * @version 1.7.6
+ **/
+
+//Switch to the appropriate trace level
+#define TRACE_LEVEL CRYPTO_TRACE_LEVEL
+
+//Dependencies
+#include <stdlib.h>
+#include <string.h>
+#include "crypto.h"
+#include "ec_curves.h"
+#include "oid.h"
+#include "debug.h"
+
+//Check crypto library configuration
+#if (EC_SUPPORT == ENABLED)
+
+//Macro definition
+#define CLEAR_WORD32(a, i, n) memset((a)->data + i, 0, n * MPI_INT_SIZE);
+#define COPY_WORD32(a, i, b, j, n) memcpy((a)->data + i, (b)->data + j, n * MPI_INT_SIZE);
+
+//secp112r1 OID (1.3.132.0.6)
+const uint8_t SECP112R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x06};
+//secp112r2 OID (1.3.132.0.7)
+const uint8_t SECP112R2_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x07};
+//secp128r1 OID (1.3.132.0.28)
+const uint8_t SECP128R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x1C};
+//secp128r2 OID (1.3.132.0.29)
+const uint8_t SECP128R2_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x1D};
+//secp160k1 OID (1.3.132.0.9)
+const uint8_t SECP160K1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x09};
+//secp160r1 OID (1.3.132.0.8)
+const uint8_t SECP160R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x08};
+//secp160r2 OID (1.3.132.0.30)
+const uint8_t SECP160R2_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x1E};
+//secp192k1 OID (1.3.132.0.31)
+const uint8_t SECP192K1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x1F};
+//secp192r1 OID (1.2.840.10045.3.1.1)
+const uint8_t SECP192R1_OID[8] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01};
+//secp224k1 OID (1.3.132.0.32)
+const uint8_t SECP224K1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x20};
+//secp224r1 OID (1.3.132.0.33)
+const uint8_t SECP224R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x21};
+//secp256k1 OID (1.3.132.0.10)
+const uint8_t SECP256K1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x0A};
+//secp256r1 OID (1.2.840.10045.3.1.7)
+const uint8_t SECP256R1_OID[8] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07};
+//secp384r1 OID (1.3.132.0.34)
+const uint8_t SECP384R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x22};
+//secp521r1 OID (1.3.132.0.35)
+const uint8_t SECP521R1_OID[5] = {0x2B, 0x81, 0x04, 0x00, 0x23};
+//brainpoolP160r1 OID (1.3.36.3.3.2.8.1.1.1)
+const uint8_t BRAINPOOLP160R1_OID[10] = {0x2B, 0x03, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01};
+//brainpoolP192r1 OID (1.3.36.3.3.2.8.1.1.3)
+const uint8_t BRAINPOOLP192R1_OID[10] = {0x2B, 0x03, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x03};
+//brainpoolP224r1 OID (1.3.36.3.3.2.8.1.1.5)
+const uint8_t BRAINPOOLP224R1_OID[10] = {0x2B, 0x03, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x05};
+//brainpoolP256r1 OID (1.3.36.3.3.2.8.1.1.7)
+const uint8_t BRAINPOOLP256R1_OID[10] = {0x2B, 0x03, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07};
+//brainpoolP320r1 OID (1.3.36.3.3.2.8.1.1.9)
+const uint8_t BRAINPOOLP320R1_OID[10] = {0x2B, 0x03, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x09};
+//brainpoolP384r1 OID (1.3.36.3.3.2.8.1.1.11)
+const uint8_t BRAINPOOLP384R1_OID[10] = {0x2B, 0x03, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B};
+//brainpoolP512r1 OID (1.3.36.3.3.2.8.1.1.13)
+const uint8_t BRAINPOOLP512R1_OID[10] = {0x2B, 0x03, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D};
+
+
+/**
+ * @brief secp112r1 elliptic curve
+ **/
+
+const EcCurveInfo secp112r1Curve =
+{
+   //Curve name
+   "secp112r1",
+   //Object identifier
+   SECP112R1_OID,
+   sizeof(SECP112R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R1,
+   //Prime modulus p
+   {0xDB, 0x7C, 0x2A, 0xBF, 0x62, 0xE3, 0x5E, 0x66, 0x80, 0x76, 0xBE, 0xAD, 0x20, 0x8B},
+   14,
+   //Curve parameter a
+   {0xDB, 0x7C, 0x2A, 0xBF, 0x62, 0xE3, 0x5E, 0x66, 0x80, 0x76, 0xBE, 0xAD, 0x20, 0x88},
+   14,
+   //Curve parameter b
+   {0x65, 0x9E, 0xF8, 0xBA, 0x04, 0x39, 0x16, 0xEE, 0xDE, 0x89, 0x11, 0x70, 0x2B, 0x22},
+   14,
+   //x-coordinate of the base point G
+   {0x09, 0x48, 0x72, 0x39, 0x99, 0x5A, 0x5E, 0xE7, 0x6B, 0x55, 0xF9, 0xC2, 0xF0, 0x98},
+   14,
+   //y-coordinate of the base point G
+   {0xA8, 0x9C, 0xE5, 0xAF, 0x87, 0x24, 0xC0, 0xA2, 0x3E, 0x0E, 0x0F, 0xF7, 0x75, 0x00},
+   14,
+   //Base point order q
+   {0xDB, 0x7C, 0x2A, 0xBF, 0x62, 0xE3, 0x5E, 0x76, 0x28, 0xDF, 0xAC, 0x65, 0x61, 0xC5},
+   14,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief secp112r2 elliptic curve
+ **/
+
+const EcCurveInfo secp112r2Curve =
+{
+   //Curve name
+   "secp112r2",
+   //Object identifier
+   SECP112R2_OID,
+   sizeof(SECP112R2_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R2,
+   //Prime modulus p
+   {0xDB, 0x7C, 0x2A, 0xBF, 0x62, 0xE3, 0x5E, 0x66, 0x80, 0x76, 0xBE, 0xAD, 0x20, 0x8B},
+   14,
+   //Curve parameter a
+   {0x61, 0x27, 0xC2, 0x4C, 0x05, 0xF3, 0x8A, 0x0A, 0xAA, 0xF6, 0x5C, 0x0E, 0xF0, 0x2C},
+   14,
+   //Curve parameter b
+   {0x51, 0xDE, 0xF1, 0x81, 0x5D, 0xB5, 0xED, 0x74, 0xFC, 0xC3, 0x4C, 0x85, 0xD7, 0x09},
+   14,
+   //x-coordinate of the base point G
+   {0x4B, 0xA3, 0x0A, 0xB5, 0xE8, 0x92, 0xB4, 0xE1, 0x64, 0x9D, 0xD0, 0x92, 0x86, 0x43},
+   14,
+   //y-coordinate of the base point G
+   {0xAD, 0xCD, 0x46, 0xF5, 0x88, 0x2E, 0x37, 0x47, 0xDE, 0xF3, 0x6E, 0x95, 0x6E, 0x97},
+   14,
+   //Base point order q
+   {0x36, 0xDF, 0x0A, 0xAF, 0xD8, 0xB8, 0xD7, 0x59, 0x7C, 0xA1, 0x05, 0x20, 0xD0, 0x4B},
+   14,
+   //Cofactor
+   4,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief secp128r1 elliptic curve
+ **/
+
+const EcCurveInfo secp128r1Curve =
+{
+   //Curve name
+   "secp128r1",
+   //Object identifier
+   SECP128R1_OID,
+   sizeof(SECP128R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R1,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+   16,
+   //Curve parameter a
+   {0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC},
+   16,
+   //Curve parameter b
+   {0xE8, 0x75, 0x79, 0xC1, 0x10, 0x79, 0xF4, 0x3D, 0xD8, 0x24, 0x99, 0x3C, 0x2C, 0xEE, 0x5E, 0xD3},
+   16,
+   //x-coordinate of the base point G
+   {0x16, 0x1F, 0xF7, 0x52, 0x8B, 0x89, 0x9B, 0x2D, 0x0C, 0x28, 0x60, 0x7C, 0xA5, 0x2C, 0x5B, 0x86},
+   16,
+   //y-coordinate of the base point G
+   {0xCF, 0x5A, 0xC8, 0x39, 0x5B, 0xAF, 0xEB, 0x13, 0xC0, 0x2D, 0xA2, 0x92, 0xDD, 0xED, 0x7A, 0x83},
+   16,
+   //Base point order q
+   {0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x75, 0xA3, 0x0D, 0x1B, 0x90, 0x38, 0xA1, 0x15},
+   16,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp128r1Mod
+};
+
+
+/**
+ * @brief secp128r2 elliptic curve
+ **/
+
+const EcCurveInfo secp128r2Curve =
+{
+   //Curve name
+   "secp128r2",
+   //Object identifier
+   SECP128R2_OID,
+   sizeof(SECP128R2_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R2,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+   16,
+   //Curve parameter a
+   {0xD6, 0x03, 0x19, 0x98, 0xD1, 0xB3, 0xBB, 0xFE, 0xBF, 0x59, 0xCC, 0x9B, 0xBF, 0xF9, 0xAE, 0xE1},
+   16,
+   //Curve parameter b
+   {0x5E, 0xEE, 0xFC, 0xA3, 0x80, 0xD0, 0x29, 0x19, 0xDC, 0x2C, 0x65, 0x58, 0xBB, 0x6D, 0x8A, 0x5D},
+   16,
+   //x-coordinate of the base point G
+   {0x7B, 0x6A, 0xA5, 0xD8, 0x5E, 0x57, 0x29, 0x83, 0xE6, 0xFB, 0x32, 0xA7, 0xCD, 0xEB, 0xC1, 0x40},
+   16,
+   //y-coordinate of the base point G
+   {0x27, 0xB6, 0x91, 0x6A, 0x89, 0x4D, 0x3A, 0xEE, 0x71, 0x06, 0xFE, 0x80, 0x5F, 0xC3, 0x4B, 0x44},
+   16,
+   //Base point order q
+   {0x3F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xBE, 0x00, 0x24, 0x72, 0x06, 0x13, 0xB5, 0xA3},
+   16,
+   //Cofactor
+   4,
+   //Fast modular reduction
+   secp128r2Mod
+};
+
+
+/**
+ * @brief secp160k1 elliptic curve
+ **/
+
+const EcCurveInfo secp160k1Curve =
+{
+   //Curve name
+   "secp160k1",
+   //Object identifier
+   SECP160K1_OID,
+   sizeof(SECP160K1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_K1,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+    0xFF, 0xFF, 0xAC, 0x73},
+   20,
+   //Curve parameter a
+   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00},
+   20,
+   //Curve parameter b
+   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x07},
+   20,
+   //x-coordinate of the base point G
+   {0x3B, 0x4C, 0x38, 0x2C, 0xE3, 0x7A, 0xA1, 0x92, 0xA4, 0x01, 0x9E, 0x76, 0x30, 0x36, 0xF4, 0xF5,
+    0xDD, 0x4D, 0x7E, 0xBB},
+   20,
+   //y-coordinate of the base point G
+   {0x93, 0x8C, 0xF9, 0x35, 0x31, 0x8F, 0xDC, 0xED, 0x6B, 0xC2, 0x82, 0x86, 0x53, 0x17, 0x33, 0xC3,
+    0xF0, 0x3C, 0x4F, 0xEE},
+   20,
+   //Base point order q
+   {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB8, 0xFA, 0x16, 0xDF, 0xAB,
+    0x9A, 0xCA, 0x16, 0xB6, 0xB3},
+   21,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp160k1Mod
+};
+
+
+/**
+ * @brief secp160r1 elliptic curve
+ **/
+
+const EcCurveInfo secp160r1Curve =
+{
+   //Curve name
+   "secp160r1",
+   //Object identifier
+   SECP160R1_OID,
+   sizeof(SECP160R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R1,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0x7F, 0xFF, 0xFF, 0xFF},
+   20,
+   //Curve parameter a
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0x7F, 0xFF, 0xFF, 0xFC},
+   20,
+   //Curve parameter b
+   {0x1C, 0x97, 0xBE, 0xFC, 0x54, 0xBD, 0x7A, 0x8B, 0x65, 0xAC, 0xF8, 0x9F, 0x81, 0xD4, 0xD4, 0xAD,
+    0xC5, 0x65, 0xFA, 0x45},
+   20,
+   //x-coordinate of the base point G
+   {0x4A, 0x96, 0xB5, 0x68, 0x8E, 0xF5, 0x73, 0x28, 0x46, 0x64, 0x69, 0x89, 0x68, 0xC3, 0x8B, 0xB9,
+    0x13, 0xCB, 0xFC, 0x82},
+   20,
+   //y-coordinate of the base point G
+   {0x23, 0xA6, 0x28, 0x55, 0x31, 0x68, 0x94, 0x7D, 0x59, 0xDC, 0xC9, 0x12, 0x04, 0x23, 0x51, 0x37,
+    0x7A, 0xC5, 0xFB, 0x32},
+   20,
+   //Base point order q
+   {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF4, 0xC8, 0xF9, 0x27, 0xAE,
+    0xD3, 0xCA, 0x75, 0x22, 0x57},
+   21,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp160r1Mod
+};
+
+
+/**
+ * @brief secp160r2 elliptic curve
+ **/
+
+const EcCurveInfo secp160r2Curve =
+{
+   //Curve name
+   "secp160r2",
+   //Object identifier
+   SECP160R2_OID,
+   sizeof(SECP160R2_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R2,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+    0xFF, 0xFF, 0xAC, 0x73},
+   20,
+   //Curve parameter a
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+    0xFF, 0xFF, 0xAC, 0x70},
+   20,
+   //Curve parameter b
+   {0xB4, 0xE1, 0x34, 0xD3, 0xFB, 0x59, 0xEB, 0x8B, 0xAB, 0x57, 0x27, 0x49, 0x04, 0x66, 0x4D, 0x5A,
+    0xF5, 0x03, 0x88, 0xBA},
+   20,
+   //x-coordinate of the base point G
+   {0x52, 0xDC, 0xB0, 0x34, 0x29, 0x3A, 0x11, 0x7E, 0x1F, 0x4F, 0xF1, 0x1B, 0x30, 0xF7, 0x19, 0x9D,
+    0x31, 0x44, 0xCE, 0x6D},
+   20,
+   //y-coordinate of the base point G
+   {0xFE, 0xAF, 0xFE, 0xF2, 0xE3, 0x31, 0xF2, 0x96, 0xE0, 0x71, 0xFA, 0x0D, 0xF9, 0x98, 0x2C, 0xFE,
+    0xA7, 0xD4, 0x3F, 0x2E},
+   20,
+   //Base point order q
+   {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1E, 0xE7, 0x86, 0xA8,
+    0x18, 0xF3, 0xA1, 0xA1, 0x6B},
+   21,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp160r2Mod
+};
+
+
+/**
+ * @brief secp192k1 elliptic curve
+ **/
+
+const EcCurveInfo secp192k1Curve =
+{
+   //Curve name
+   "secp192k1",
+   //Object identifier
+   SECP192K1_OID,
+   sizeof(SECP192K1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_K1,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xEE, 0x37},
+   24,
+   //Curve parameter a
+   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+   24,
+   //Curve parameter b
+   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03},
+   24,
+   //x-coordinate of the base point G
+   {0xDB, 0x4F, 0xF1, 0x0E, 0xC0, 0x57, 0xE9, 0xAE, 0x26, 0xB0, 0x7D, 0x02, 0x80, 0xB7, 0xF4, 0x34,
+    0x1D, 0xA5, 0xD1, 0xB1, 0xEA, 0xE0, 0x6C, 0x7D},
+   24,
+   //y-coordinate of the base point G
+   {0x9B, 0x2F, 0x2F, 0x6D, 0x9C, 0x56, 0x28, 0xA7, 0x84, 0x41, 0x63, 0xD0, 0x15, 0xBE, 0x86, 0x34,
+    0x40, 0x82, 0xAA, 0x88, 0xD9, 0x5E, 0x2F, 0x9D},
+   24,
+   //Base point order q
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x26, 0xF2, 0xFC, 0x17,
+    0x0F, 0x69, 0x46, 0x6A, 0x74, 0xDE, 0xFD, 0x8D},
+   24,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp192k1Mod
+};
+
+
+/**
+ * @brief secp192r1 elliptic curve
+ **/
+
+const EcCurveInfo secp192r1Curve =
+{
+   //Curve name
+   "secp192r1",
+   //Object identifier
+   SECP192R1_OID,
+   sizeof(SECP192R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R1,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+   24,
+   //Curve parameter a
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC},
+   24,
+   //Curve parameter b
+   {0x64, 0x21, 0x05, 0x19, 0xE5, 0x9C, 0x80, 0xE7, 0x0F, 0xA7, 0xE9, 0xAB, 0x72, 0x24, 0x30, 0x49,
+    0xFE, 0xB8, 0xDE, 0xEC, 0xC1, 0x46, 0xB9, 0xB1},
+   24,
+   //x-coordinate of the base point G
+   {0x18, 0x8D, 0xA8, 0x0E, 0xB0, 0x30, 0x90, 0xF6, 0x7C, 0xBF, 0x20, 0xEB, 0x43, 0xA1, 0x88, 0x00,
+    0xF4, 0xFF, 0x0A, 0xFD, 0x82, 0xFF, 0x10, 0x12},
+   24,
+   //y-coordinate of the base point G
+   {0x07, 0x19, 0x2B, 0x95, 0xFF, 0xC8, 0xDA, 0x78, 0x63, 0x10, 0x11, 0xED, 0x6B, 0x24, 0xCD, 0xD5,
+    0x73, 0xF9, 0x77, 0xA1, 0x1E, 0x79, 0x48, 0x11},
+   24,
+   //Base point order q
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0xDE, 0xF8, 0x36,
+    0x14, 0x6B, 0xC9, 0xB1, 0xB4, 0xD2, 0x28, 0x31},
+   24,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp192r1Mod
+};
+
+
+/**
+ * @brief secp224k1 elliptic curve
+ **/
+
+const EcCurveInfo secp224k1Curve =
+{
+   //Curve name
+   "secp224k1",
+   //Object identifier
+   SECP224K1_OID,
+   sizeof(SECP224K1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_K1,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xE5, 0x6D},
+   28,
+   //Curve parameter a
+   {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},
+   28,
+   //Curve parameter b
+   {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, 0x05},
+   28,
+   //x-coordinate of the base point G
+   {0xA1, 0x45, 0x5B, 0x33, 0x4D, 0xF0, 0x99, 0xDF, 0x30, 0xFC, 0x28, 0xA1, 0x69, 0xA4, 0x67, 0xE9,
+    0xE4, 0x70, 0x75, 0xA9, 0x0F, 0x7E, 0x65, 0x0E, 0xB6, 0xB7, 0xA4, 0x5C},
+   28,
+   //y-coordinate of the base point G
+   {0x7E, 0x08, 0x9F, 0xED, 0x7F, 0xBA, 0x34, 0x42, 0x82, 0xCA, 0xFB, 0xD6, 0xF7, 0xE3, 0x19, 0xF7,
+    0xC0, 0xB0, 0xBD, 0x59, 0xE2, 0xCA, 0x4B, 0xDB, 0x55, 0x6D, 0x61, 0xA5},
+   28,
+   //Base point order q
+   {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xDC,
+    0xE8, 0xD2, 0xEC, 0x61, 0x84, 0xCA, 0xF0, 0xA9, 0x71, 0x76, 0x9F, 0xB1, 0xF7},
+   29,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp224k1Mod
+};
+
+
+/**
+ * @brief secp224r1 elliptic curve
+ **/
+
+const EcCurveInfo secp224r1Curve =
+{
+   //Curve name
+   "secp224r1",
+   //Object identifier
+   SECP224R1_OID,
+   sizeof(SECP224R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R1,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+   28,
+   //Curve parameter a
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE},
+   28,
+   //Curve parameter b
+   {0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB, 0xF5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xB0, 0xB7,
+    0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B, 0x39, 0x43, 0x23, 0x55, 0xFF, 0xB4},
+   28,
+   //x-coordinate of the base point G
+   {0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, 0x32, 0x13, 0x90, 0xB9, 0x4A, 0x03, 0xC1, 0xD3,
+    0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6, 0x11, 0x5C, 0x1D, 0x21},
+   28,
+   //y-coordinate of the base point G
+   {0xBD, 0x37, 0x63, 0x88, 0xB5, 0xF7, 0x23, 0xFB, 0x4C, 0x22, 0xDF, 0xE6, 0xCD, 0x43, 0x75, 0xA0,
+    0x5A, 0x07, 0x47, 0x64, 0x44, 0xD5, 0x81, 0x99, 0x85, 0x00, 0x7E, 0x34},
+   28,
+   //Base point order q
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x16, 0xA2,
+    0xE0, 0xB8, 0xF0, 0x3E, 0x13, 0xDD, 0x29, 0x45, 0x5C, 0x5C, 0x2A, 0x3D},
+   28,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp224r1Mod
+};
+
+
+/**
+ * @brief secp256k1 elliptic curve
+ **/
+
+const EcCurveInfo secp256k1Curve =
+{
+   //Curve name
+   "secp256k1",
+   //Object identifier
+   SECP256K1_OID,
+   sizeof(SECP256K1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_K1,
+   //Prime modulus p
+   {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, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F},
+   32,
+   //Curve parameter a
+   {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, 0x00},
+   32,
+   //Curve parameter b
+   {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, 0x07},
+   32,
+   //x-coordinate of the base point G
+   {0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
+    0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98},
+   32,
+   //y-coordinate of the base point G
+   {0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8,
+    0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8},
+   32,
+   //Base point order q
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+    0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41},
+   32,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp256k1Mod
+};
+
+
+/**
+ * @brief secp256r1 elliptic curve
+ **/
+
+const EcCurveInfo secp256r1Curve =
+{
+   //Curve name
+   "secp256r1",
+   //Object identifier
+   SECP256R1_OID,
+   sizeof(SECP256R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R1,
+   //Prime modulus p
+   {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+   32,
+   //Curve parameter a
+   {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC},
+   32,
+   //Curve parameter b
+   {0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC,
+    0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B},
+   32,
+   //x-coordinate of the base point G
+   {0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
+    0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96},
+   32,
+   //y-coordinate of the base point G
+   {0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
+    0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5},
+   32,
+   //Base point order q
+   {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51},
+   32,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp256r1Mod
+};
+
+
+/**
+ * @brief secp384r1 elliptic curve
+ **/
+
+const EcCurveInfo secp384r1Curve =
+{
+   //Curve name
+   "secp384r1",
+   //Object identifier
+   SECP384R1_OID,
+   sizeof(SECP384R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R1,
+   //Prime modulus p
+   {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, 0xFE,
+    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF},
+   48,
+   //Curve parameter a
+   {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, 0xFE,
+    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC},
+   48,
+   //Curve parameter b
+   {0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B, 0xE3, 0xF8, 0x2D, 0x19,
+    0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12, 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A,
+    0xC6, 0x56, 0x39, 0x8D, 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF},
+   48,
+   //x-coordinate of the base point G
+   {0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD, 0x74,
+    0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38,
+    0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7},
+   48,
+   //y-coordinate of the base point G
+   {0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC, 0x29,
+    0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0,
+    0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81, 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F},
+   48,
+   //Base point order q
+   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
+    0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73},
+   48,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp384r1Mod
+};
+
+
+/**
+ * @brief secp521r1 elliptic curve
+ **/
+
+const EcCurveInfo secp521r1Curve =
+{
+   //Curve name
+   "secp521r1",
+   //Object identifier
+   SECP521R1_OID,
+   sizeof(SECP521R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_SECP_R1,
+   //Prime modulus p
+   {0x01, 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},
+   66,
+   //Curve parameter a
+   {0x01, 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, 0xFC},
+   66,
+   //Curve parameter b
+   {0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A, 0x21, 0xA0, 0xB6, 0x85,
+    0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3, 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1,
+    0x09, 0xE1, 0x56, 0x19, 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1,
+    0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45, 0x1F, 0xD4, 0x6B, 0x50,
+    0x3F, 0x00},
+   66,
+   //x-coordinate of the base point G
+   {0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23, 0x95,
+    0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D,
+    0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF,
+    0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2, 0xE5,
+    0xBD, 0x66},
+   66,
+   //y-coordinate of the base point G
+   {0x01, 0x18, 0x39, 0x29, 0x6A, 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F, 0xB4, 0x2C, 0x7D,
+    0x1B, 0xD9, 0x98, 0xF5, 0x44, 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD, 0x17, 0x27, 0x3E,
+    0x66, 0x2C, 0x97, 0xEE, 0x72, 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9, 0x01, 0x3F, 0xAD,
+    0x07, 0x61, 0x35, 0x3C, 0x70, 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94, 0x76, 0x9F, 0xD1,
+    0x66, 0x50},
+   66,
+   //Base point order q
+   {0x01, 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, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
+    0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38,
+    0x64, 0x09},
+   66,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   secp521r1Mod
+};
+
+
+/**
+ * @brief brainpoolP160r1 elliptic curve
+ **/
+
+const EcCurveInfo brainpoolP160r1Curve =
+{
+   //Curve name
+   "brainpoolP160r1",
+   //Object identifier
+   BRAINPOOLP160R1_OID,
+   sizeof(BRAINPOOLP160R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_BRAINPOOLP_R1,
+   //Prime modulus p
+   {0xE9, 0x5E, 0x4A, 0x5F, 0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0xC7, 0xAD, 0x95, 0xB3, 0xD8, 0x13,
+    0x95, 0x15, 0x62, 0x0F},
+   20,
+   //Curve parameter a
+   {0x34, 0x0E, 0x7B, 0xE2, 0xA2, 0x80, 0xEB, 0x74, 0xE2, 0xBE, 0x61, 0xBA, 0xDA, 0x74, 0x5D, 0x97,
+    0xE8, 0xF7, 0xC3, 0x00},
+   20,
+   //Curve parameter b
+   {0x1E, 0x58, 0x9A, 0x85, 0x95, 0x42, 0x34, 0x12, 0x13, 0x4F, 0xAA, 0x2D, 0xBD, 0xEC, 0x95, 0xC8,
+    0xD8, 0x67, 0x5E, 0x58},
+   20,
+   //x-coordinate of the base point G
+   {0xBE, 0xD5, 0xAF, 0x16, 0xEA, 0x3F, 0x6A, 0x4F, 0x62, 0x93, 0x8C, 0x46, 0x31, 0xEB, 0x5A, 0xF7,
+    0xBD, 0xBC, 0xDB, 0xC3},
+   20,
+   //y-coordinate of the base point G
+   {0x16, 0x67, 0xCB, 0x47, 0x7A, 0x1A, 0x8E, 0xC3, 0x38, 0xF9, 0x47, 0x41, 0x66, 0x9C, 0x97, 0x63,
+    0x16, 0xDA, 0x63, 0x21},
+   20,
+   //Base point order q
+   {0xE9, 0x5E, 0x4A, 0x5F, 0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0x59, 0x91, 0xD4, 0x50, 0x29, 0x40,
+    0x9E, 0x60, 0xFC, 0x09},
+   20,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief brainpoolP192r1 elliptic curve
+ **/
+
+const EcCurveInfo brainpoolP192r1Curve =
+{
+   //Curve name
+   "brainpoolP192r1",
+   //Object identifier
+   BRAINPOOLP192R1_OID,
+   sizeof(BRAINPOOLP192R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_BRAINPOOLP_R1,
+   //Prime modulus p
+   {0xC3, 0x02, 0xF4, 0x1D, 0x93, 0x2A, 0x36, 0xCD, 0xA7, 0xA3, 0x46, 0x30, 0x93, 0xD1, 0x8D, 0xB7,
+    0x8F, 0xCE, 0x47, 0x6D, 0xE1, 0xA8, 0x62, 0x97},
+   24,
+   //Curve parameter a
+   {0x6A, 0x91, 0x17, 0x40, 0x76, 0xB1, 0xE0, 0xE1, 0x9C, 0x39, 0xC0, 0x31, 0xFE, 0x86, 0x85, 0xC1,
+    0xCA, 0xE0, 0x40, 0xE5, 0xC6, 0x9A, 0x28, 0xEF},
+   24,
+   //Curve parameter b
+   {0x46, 0x9A, 0x28, 0xEF, 0x7C, 0x28, 0xCC, 0xA3, 0xDC, 0x72, 0x1D, 0x04, 0x4F, 0x44, 0x96, 0xBC,
+    0xCA, 0x7E, 0xF4, 0x14, 0x6F, 0xBF, 0x25, 0xC9},
+   24,
+   //x-coordinate of the base point G
+   {0xC0, 0xA0, 0x64, 0x7E, 0xAA, 0xB6, 0xA4, 0x87, 0x53, 0xB0, 0x33, 0xC5, 0x6C, 0xB0, 0xF0, 0x90,
+    0x0A, 0x2F, 0x5C, 0x48, 0x53, 0x37, 0x5F, 0xD6},
+   24,
+   //y-coordinate of the base point G
+   {0x14, 0xB6, 0x90, 0x86, 0x6A, 0xBD, 0x5B, 0xB8, 0x8B, 0x5F, 0x48, 0x28, 0xC1, 0x49, 0x00, 0x02,
+    0xE6, 0x77, 0x3F, 0xA2, 0xFA, 0x29, 0x9B, 0x8F},
+   24,
+   //Base point order q
+   {0xC3, 0x02, 0xF4, 0x1D, 0x93, 0x2A, 0x36, 0xCD, 0xA7, 0xA3, 0x46, 0x2F, 0x9E, 0x9E, 0x91, 0x6B,
+    0x5B, 0xE8, 0xF1, 0x02, 0x9A, 0xC4, 0xAC, 0xC1},
+   24,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief brainpoolP224r1 elliptic curve
+ **/
+
+const EcCurveInfo brainpoolP224r1Curve =
+{
+   //Curve name
+   "brainpoolP224r1",
+   //Object identifier
+   BRAINPOOLP224R1_OID,
+   sizeof(BRAINPOOLP224R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_BRAINPOOLP_R1,
+   //Prime modulus p
+   {0xD7, 0xC1, 0x34, 0xAA, 0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25, 0x75, 0xD1, 0xD7, 0x87,
+    0xB0, 0x9F, 0x07, 0x57, 0x97, 0xDA, 0x89, 0xF5, 0x7E, 0xC8, 0xC0, 0xFF},
+   28,
+   //Curve parameter a
+   {0x68, 0xA5, 0xE6, 0x2C, 0xA9, 0xCE, 0x6C, 0x1C, 0x29, 0x98, 0x03, 0xA6, 0xC1, 0x53, 0x0B, 0x51,
+    0x4E, 0x18, 0x2A, 0xD8, 0xB0, 0x04, 0x2A, 0x59, 0xCA, 0xD2, 0x9F, 0x43},
+   28,
+   //Curve parameter b
+   {0x25, 0x80, 0xF6, 0x3C, 0xCF, 0xE4, 0x41, 0x38, 0x87, 0x07, 0x13, 0xB1, 0xA9, 0x23, 0x69, 0xE3,
+    0x3E, 0x21, 0x35, 0xD2, 0x66, 0xDB, 0xB3, 0x72, 0x38, 0x6C, 0x40, 0x0B},
+   28,
+   //x-coordinate of the base point G
+   {0x0D, 0x90, 0x29, 0xAD, 0x2C, 0x7E, 0x5C, 0xF4, 0x34, 0x08, 0x23, 0xB2, 0xA8, 0x7D, 0xC6, 0x8C,
+    0x9E, 0x4C, 0xE3, 0x17, 0x4C, 0x1E, 0x6E, 0xFD, 0xEE, 0x12, 0xC0, 0x7D},
+   28,
+   //y-coordinate of the base point G
+   {0x58, 0xAA, 0x56, 0xF7, 0x72, 0xC0, 0x72, 0x6F, 0x24, 0xC6, 0xB8, 0x9E, 0x4E, 0xCD, 0xAC, 0x24,
+    0x35, 0x4B, 0x9E, 0x99, 0xCA, 0xA3, 0xF6, 0xD3, 0x76, 0x14, 0x02, 0xCD},
+   28,
+   //Base point order q
+   {0xD7, 0xC1, 0x34, 0xAA, 0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25, 0x75, 0xD0, 0xFB, 0x98,
+    0xD1, 0x16, 0xBC, 0x4B, 0x6D, 0xDE, 0xBC, 0xA3, 0xA5, 0xA7, 0x93, 0x9F},
+   28,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief brainpoolP256r1 elliptic curve
+ **/
+
+const EcCurveInfo brainpoolP256r1Curve =
+{
+   //Curve name
+   "brainpoolP256r1",
+   //Object identifier
+   BRAINPOOLP256R1_OID,
+   sizeof(BRAINPOOLP256R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_BRAINPOOLP_R1,
+   //Prime modulus p
+   {0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC, 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
+    0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28, 0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x77},
+   32,
+   //Curve parameter a
+   {0x7D, 0x5A, 0x09, 0x75, 0xFC, 0x2C, 0x30, 0x57, 0xEE, 0xF6, 0x75, 0x30, 0x41, 0x7A, 0xFF, 0xE7,
+    0xFB, 0x80, 0x55, 0xC1, 0x26, 0xDC, 0x5C, 0x6C, 0xE9, 0x4A, 0x4B, 0x44, 0xF3, 0x30, 0xB5, 0xD9},
+   32,
+   //Curve parameter b
+   {0x26, 0xDC, 0x5C, 0x6C, 0xE9, 0x4A, 0x4B, 0x44, 0xF3, 0x30, 0xB5, 0xD9, 0xBB, 0xD7, 0x7C, 0xBF,
+    0x95, 0x84, 0x16, 0x29, 0x5C, 0xF7, 0xE1, 0xCE, 0x6B, 0xCC, 0xDC, 0x18, 0xFF, 0x8C, 0x07, 0xB6},
+   32,
+   //x-coordinate of the base point G
+   {0x8B, 0xD2, 0xAE, 0xB9, 0xCB, 0x7E, 0x57, 0xCB, 0x2C, 0x4B, 0x48, 0x2F, 0xFC, 0x81, 0xB7, 0xAF,
+    0xB9, 0xDE, 0x27, 0xE1, 0xE3, 0xBD, 0x23, 0xC2, 0x3A, 0x44, 0x53, 0xBD, 0x9A, 0xCE, 0x32, 0x62},
+   32,
+   //y-coordinate of the base point G
+   {0x54, 0x7E, 0xF8, 0x35, 0xC3, 0xDA, 0xC4, 0xFD, 0x97, 0xF8, 0x46, 0x1A, 0x14, 0x61, 0x1D, 0xC9,
+    0xC2, 0x77, 0x45, 0x13, 0x2D, 0xED, 0x8E, 0x54, 0x5C, 0x1D, 0x54, 0xC7, 0x2F, 0x04, 0x69, 0x97},
+   32,
+   //Base point order q
+   {0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC, 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x71,
+    0x8C, 0x39, 0x7A, 0xA3, 0xB5, 0x61, 0xA6, 0xF7, 0x90, 0x1E, 0x0E, 0x82, 0x97, 0x48, 0x56, 0xA7},
+   32,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief brainpoolP320r1 elliptic curve
+ **/
+
+const EcCurveInfo brainpoolP320r1Curve =
+{
+   //Curve name
+   "brainpoolP320r1",
+   //Object identifier
+   BRAINPOOLP320R1_OID,
+   sizeof(BRAINPOOLP320R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_BRAINPOOLP_R1,
+   //Prime modulus p
+   {0xD3, 0x5E, 0x47, 0x20, 0x36, 0xBC, 0x4F, 0xB7, 0xE1, 0x3C, 0x78, 0x5E, 0xD2, 0x01, 0xE0, 0x65,
+    0xF9, 0x8F, 0xCF, 0xA6, 0xF6, 0xF4, 0x0D, 0xEF, 0x4F, 0x92, 0xB9, 0xEC, 0x78, 0x93, 0xEC, 0x28,
+    0xFC, 0xD4, 0x12, 0xB1, 0xF1, 0xB3, 0x2E, 0x27},
+   40,
+   //Curve parameter a
+   {0x3E, 0xE3, 0x0B, 0x56, 0x8F, 0xBA, 0xB0, 0xF8, 0x83, 0xCC, 0xEB, 0xD4, 0x6D, 0x3F, 0x3B, 0xB8,
+    0xA2, 0xA7, 0x35, 0x13, 0xF5, 0xEB, 0x79, 0xDA, 0x66, 0x19, 0x0E, 0xB0, 0x85, 0xFF, 0xA9, 0xF4,
+    0x92, 0xF3, 0x75, 0xA9, 0x7D, 0x86, 0x0E, 0xB4},
+   40,
+   //Curve parameter b
+   {0x52, 0x08, 0x83, 0x94, 0x9D, 0xFD, 0xBC, 0x42, 0xD3, 0xAD, 0x19, 0x86, 0x40, 0x68, 0x8A, 0x6F,
+    0xE1, 0x3F, 0x41, 0x34, 0x95, 0x54, 0xB4, 0x9A, 0xCC, 0x31, 0xDC, 0xCD, 0x88, 0x45, 0x39, 0x81,
+    0x6F, 0x5E, 0xB4, 0xAC, 0x8F, 0xB1, 0xF1, 0xA6},
+   40,
+   //x-coordinate of the base point G
+   {0x43, 0xBD, 0x7E, 0x9A, 0xFB, 0x53, 0xD8, 0xB8, 0x52, 0x89, 0xBC, 0xC4, 0x8E, 0xE5, 0xBF, 0xE6,
+    0xF2, 0x01, 0x37, 0xD1, 0x0A, 0x08, 0x7E, 0xB6, 0xE7, 0x87, 0x1E, 0x2A, 0x10, 0xA5, 0x99, 0xC7,
+    0x10, 0xAF, 0x8D, 0x0D, 0x39, 0xE2, 0x06, 0x11},
+   40,
+   //y-coordinate of the base point G
+   {0x14, 0xFD, 0xD0, 0x55, 0x45, 0xEC, 0x1C, 0xC8, 0xAB, 0x40, 0x93, 0x24, 0x7F, 0x77, 0x27, 0x5E,
+    0x07, 0x43, 0xFF, 0xED, 0x11, 0x71, 0x82, 0xEA, 0xA9, 0xC7, 0x78, 0x77, 0xAA, 0xAC, 0x6A, 0xC7,
+    0xD3, 0x52, 0x45, 0xD1, 0x69, 0x2E, 0x8E, 0xE1},
+   40,
+   //Base point order q
+   {0xD3, 0x5E, 0x47, 0x20, 0x36, 0xBC, 0x4F, 0xB7, 0xE1, 0x3C, 0x78, 0x5E, 0xD2, 0x01, 0xE0, 0x65,
+    0xF9, 0x8F, 0xCF, 0xA5, 0xB6, 0x8F, 0x12, 0xA3, 0x2D, 0x48, 0x2E, 0xC7, 0xEE, 0x86, 0x58, 0xE9,
+    0x86, 0x91, 0x55, 0x5B, 0x44, 0xC5, 0x93, 0x11},
+   40,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief brainpoolP384r1 elliptic curve
+ **/
+
+const EcCurveInfo brainpoolP384r1Curve =
+{
+   //Curve name
+   "brainpoolP384r1",
+   //Object identifier
+   BRAINPOOLP384R1_OID,
+   sizeof(BRAINPOOLP384R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_BRAINPOOLP_R1,
+   //Prime modulus p
+   {0x8C, 0xB9, 0x1E, 0x82, 0xA3, 0x38, 0x6D, 0x28, 0x0F, 0x5D, 0x6F, 0x7E, 0x50, 0xE6, 0x41, 0xDF,
+    0x15, 0x2F, 0x71, 0x09, 0xED, 0x54, 0x56, 0xB4, 0x12, 0xB1, 0xDA, 0x19, 0x7F, 0xB7, 0x11, 0x23,
+    0xAC, 0xD3, 0xA7, 0x29, 0x90, 0x1D, 0x1A, 0x71, 0x87, 0x47, 0x00, 0x13, 0x31, 0x07, 0xEC, 0x53},
+   48,
+   //Curve parameter a
+   {0x7B, 0xC3, 0x82, 0xC6, 0x3D, 0x8C, 0x15, 0x0C, 0x3C, 0x72, 0x08, 0x0A, 0xCE, 0x05, 0xAF, 0xA0,
+    0xC2, 0xBE, 0xA2, 0x8E, 0x4F, 0xB2, 0x27, 0x87, 0x13, 0x91, 0x65, 0xEF, 0xBA, 0x91, 0xF9, 0x0F,
+    0x8A, 0xA5, 0x81, 0x4A, 0x50, 0x3A, 0xD4, 0xEB, 0x04, 0xA8, 0xC7, 0xDD, 0x22, 0xCE, 0x28, 0x26},
+   48,
+   //Curve parameter b
+   {0x04, 0xA8, 0xC7, 0xDD, 0x22, 0xCE, 0x28, 0x26, 0x8B, 0x39, 0xB5, 0x54, 0x16, 0xF0, 0x44, 0x7C,
+    0x2F, 0xB7, 0x7D, 0xE1, 0x07, 0xDC, 0xD2, 0xA6, 0x2E, 0x88, 0x0E, 0xA5, 0x3E, 0xEB, 0x62, 0xD5,
+    0x7C, 0xB4, 0x39, 0x02, 0x95, 0xDB, 0xC9, 0x94, 0x3A, 0xB7, 0x86, 0x96, 0xFA, 0x50, 0x4C, 0x11},
+   48,
+   //x-coordinate of the base point G
+   {0x1D, 0x1C, 0x64, 0xF0, 0x68, 0xCF, 0x45, 0xFF, 0xA2, 0xA6, 0x3A, 0x81, 0xB7, 0xC1, 0x3F, 0x6B,
+    0x88, 0x47, 0xA3, 0xE7, 0x7E, 0xF1, 0x4F, 0xE3, 0xDB, 0x7F, 0xCA, 0xFE, 0x0C, 0xBD, 0x10, 0xE8,
+    0xE8, 0x26, 0xE0, 0x34, 0x36, 0xD6, 0x46, 0xAA, 0xEF, 0x87, 0xB2, 0xE2, 0x47, 0xD4, 0xAF, 0x1E},
+   48,
+   //y-coordinate of the base point G
+   {0x8A, 0xBE, 0x1D, 0x75, 0x20, 0xF9, 0xC2, 0xA4, 0x5C, 0xB1, 0xEB, 0x8E, 0x95, 0xCF, 0xD5, 0x52,
+    0x62, 0xB7, 0x0B, 0x29, 0xFE, 0xEC, 0x58, 0x64, 0xE1, 0x9C, 0x05, 0x4F, 0xF9, 0x91, 0x29, 0x28,
+    0x0E, 0x46, 0x46, 0x21, 0x77, 0x91, 0x81, 0x11, 0x42, 0x82, 0x03, 0x41, 0x26, 0x3C, 0x53, 0x15},
+   48,
+   //Base point order q
+   {0x8C, 0xB9, 0x1E, 0x82, 0xA3, 0x38, 0x6D, 0x28, 0x0F, 0x5D, 0x6F, 0x7E, 0x50, 0xE6, 0x41, 0xDF,
+    0x15, 0x2F, 0x71, 0x09, 0xED, 0x54, 0x56, 0xB3, 0x1F, 0x16, 0x6E, 0x6C, 0xAC, 0x04, 0x25, 0xA7,
+    0xCF, 0x3A, 0xB6, 0xAF, 0x6B, 0x7F, 0xC3, 0x10, 0x3B, 0x88, 0x32, 0x02, 0xE9, 0x04, 0x65, 0x65},
+   48,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief brainpoolP512r1 elliptic curve
+ **/
+
+const EcCurveInfo brainpoolP512r1Curve =
+{
+   //Curve name
+   "brainpoolP512r1",
+   //Object identifier
+   BRAINPOOLP512R1_OID,
+   sizeof(BRAINPOOLP512R1_OID),
+   //Curve type
+   EC_CURVE_TYPE_BRAINPOOLP_R1,
+   //Prime modulus p
+   {0xAA, 0xDD, 0x9D, 0xB8, 0xDB, 0xE9, 0xC4, 0x8B, 0x3F, 0xD4, 0xE6, 0xAE, 0x33, 0xC9, 0xFC, 0x07,
+    0xCB, 0x30, 0x8D, 0xB3, 0xB3, 0xC9, 0xD2, 0x0E, 0xD6, 0x63, 0x9C, 0xCA, 0x70, 0x33, 0x08, 0x71,
+    0x7D, 0x4D, 0x9B, 0x00, 0x9B, 0xC6, 0x68, 0x42, 0xAE, 0xCD, 0xA1, 0x2A, 0xE6, 0xA3, 0x80, 0xE6,
+    0x28, 0x81, 0xFF, 0x2F, 0x2D, 0x82, 0xC6, 0x85, 0x28, 0xAA, 0x60, 0x56, 0x58, 0x3A, 0x48, 0xF3},
+   64,
+   //Curve parameter a
+   {0x78, 0x30, 0xA3, 0x31, 0x8B, 0x60, 0x3B, 0x89, 0xE2, 0x32, 0x71, 0x45, 0xAC, 0x23, 0x4C, 0xC5,
+    0x94, 0xCB, 0xDD, 0x8D, 0x3D, 0xF9, 0x16, 0x10, 0xA8, 0x34, 0x41, 0xCA, 0xEA, 0x98, 0x63, 0xBC,
+    0x2D, 0xED, 0x5D, 0x5A, 0xA8, 0x25, 0x3A, 0xA1, 0x0A, 0x2E, 0xF1, 0xC9, 0x8B, 0x9A, 0xC8, 0xB5,
+    0x7F, 0x11, 0x17, 0xA7, 0x2B, 0xF2, 0xC7, 0xB9, 0xE7, 0xC1, 0xAC, 0x4D, 0x77, 0xFC, 0x94, 0xCA},
+   64,
+   //Curve parameter b
+   {0x3D, 0xF9, 0x16, 0x10, 0xA8, 0x34, 0x41, 0xCA, 0xEA, 0x98, 0x63, 0xBC, 0x2D, 0xED, 0x5D, 0x5A,
+    0xA8, 0x25, 0x3A, 0xA1, 0x0A, 0x2E, 0xF1, 0xC9, 0x8B, 0x9A, 0xC8, 0xB5, 0x7F, 0x11, 0x17, 0xA7,
+    0x2B, 0xF2, 0xC7, 0xB9, 0xE7, 0xC1, 0xAC, 0x4D, 0x77, 0xFC, 0x94, 0xCA, 0xDC, 0x08, 0x3E, 0x67,
+    0x98, 0x40, 0x50, 0xB7, 0x5E, 0xBA, 0xE5, 0xDD, 0x28, 0x09, 0xBD, 0x63, 0x80, 0x16, 0xF7, 0x23},
+   64,
+   //x-coordinate of the base point G
+   {0x81, 0xAE, 0xE4, 0xBD, 0xD8, 0x2E, 0xD9, 0x64, 0x5A, 0x21, 0x32, 0x2E, 0x9C, 0x4C, 0x6A, 0x93,
+    0x85, 0xED, 0x9F, 0x70, 0xB5, 0xD9, 0x16, 0xC1, 0xB4, 0x3B, 0x62, 0xEE, 0xF4, 0xD0, 0x09, 0x8E,
+    0xFF, 0x3B, 0x1F, 0x78, 0xE2, 0xD0, 0xD4, 0x8D, 0x50, 0xD1, 0x68, 0x7B, 0x93, 0xB9, 0x7D, 0x5F,
+    0x7C, 0x6D, 0x50, 0x47, 0x40, 0x6A, 0x5E, 0x68, 0x8B, 0x35, 0x22, 0x09, 0xBC, 0xB9, 0xF8, 0x22},
+   64,
+   //y-coordinate of the base point G
+   {0x7D, 0xDE, 0x38, 0x5D, 0x56, 0x63, 0x32, 0xEC, 0xC0, 0xEA, 0xBF, 0xA9, 0xCF, 0x78, 0x22, 0xFD,
+    0xF2, 0x09, 0xF7, 0x00, 0x24, 0xA5, 0x7B, 0x1A, 0xA0, 0x00, 0xC5, 0x5B, 0x88, 0x1F, 0x81, 0x11,
+    0xB2, 0xDC, 0xDE, 0x49, 0x4A, 0x5F, 0x48, 0x5E, 0x5B, 0xCA, 0x4B, 0xD8, 0x8A, 0x27, 0x63, 0xAE,
+    0xD1, 0xCA, 0x2B, 0x2F, 0xA8, 0xF0, 0x54, 0x06, 0x78, 0xCD, 0x1E, 0x0F, 0x3A, 0xD8, 0x08, 0x92},
+   64,
+   //Base point order q
+   {0xAA, 0xDD, 0x9D, 0xB8, 0xDB, 0xE9, 0xC4, 0x8B, 0x3F, 0xD4, 0xE6, 0xAE, 0x33, 0xC9, 0xFC, 0x07,
+    0xCB, 0x30, 0x8D, 0xB3, 0xB3, 0xC9, 0xD2, 0x0E, 0xD6, 0x63, 0x9C, 0xCA, 0x70, 0x33, 0x08, 0x70,
+    0x55, 0x3E, 0x5C, 0x41, 0x4C, 0xA9, 0x26, 0x19, 0x41, 0x86, 0x61, 0x19, 0x7F, 0xAC, 0x10, 0x47,
+    0x1D, 0xB1, 0xD3, 0x81, 0x08, 0x5D, 0xDA, 0xDD, 0xB5, 0x87, 0x96, 0x82, 0x9C, 0xA9, 0x00, 0x69},
+   64,
+   //Cofactor
+   1,
+   //Fast modular reduction
+   NULL
+};
+
+
+/**
+ * @brief Fast modular reduction (secp128r1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp128r1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 32 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 32 / MPI_INT_SIZE));
+
+   //Perform modular reduction
+   do
+   {
+      //Compute T = 0 | 0 | 0 | 0 | A7 | A6 | A5 | A4
+      COPY_WORD32(&t, 0, a, 4, 4);
+      CLEAR_WORD32(&t, 4, 4);
+
+      //Clear A7 | A6 | A5 | A4
+      CLEAR_WORD32(a, 4, 4);
+
+      //Compute A = A + T + (T << 97)
+      MPI_CHECK(mpiAdd(a, a, &t));
+      MPI_CHECK(mpiShiftLeft(&t, 97));
+      MPI_CHECK(mpiAdd(a, a, &t));
+
+      //Check for end condition
+   } while(mpiComp(a, p) > 0);
+
+end:
+   //Release multiple precision integers
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp128r2 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp128r2Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 32 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 32 / MPI_INT_SIZE));
+
+   //Perform modular reduction
+   do
+   {
+      //Compute T = 0 | 0 | 0 | 0 | A7 | A6 | A5 | A4
+      COPY_WORD32(&t, 0, a, 4, 4);
+      CLEAR_WORD32(&t, 4, 4);
+
+      //Clear A7 | A6 | A5 | A4
+      CLEAR_WORD32(a, 4, 4);
+
+      //Compute A = A + T + (T << 97)
+      MPI_CHECK(mpiAdd(a, a, &t));
+      MPI_CHECK(mpiShiftLeft(&t, 97));
+      MPI_CHECK(mpiAdd(a, a, &t));
+
+      //Check for end condition
+   } while(mpiComp(a, p) > 0);
+
+end:
+   //Release multiple precision integers
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp160k1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp160k1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 40 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 24 / MPI_INT_SIZE));
+
+   //Perform modular reduction
+   do
+   {
+      //Compute T = A9 | A8 | A7 | A6 | A5 | 0
+      CLEAR_WORD32(&t, 0, 1);
+      COPY_WORD32(&t, 1, a, 5, 5);
+
+      //Clear A9 | A8 | A7 | A6 | A5
+      CLEAR_WORD32(a, 5, 5);
+
+      //Compute A = A + T
+      MPI_CHECK(mpiAdd(a, a, &t));
+      //Compute T = T >> 32
+      MPI_CHECK(mpiShiftRight(&t, 32));
+      //Compute A = A + (21389 * T)
+      MPI_CHECK(mpiMulInt(&t, &t, 21389));
+      MPI_CHECK(mpiAdd(a, a, &t));
+
+      //Check for end condition
+   } while(mpiComp(a, p) > 0);
+
+end:
+   //Release multiple precision integers
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp160r1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp160r1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 40 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 24 / MPI_INT_SIZE));
+
+   //Perform modular reduction
+   do
+   {
+      //Compute T = 0 | A9 | A8 | A7 | A6 | A5
+      COPY_WORD32(&t, 0, a, 5, 5);
+      CLEAR_WORD32(&t, 5, 1);
+
+      //Clear A9 | A8 | A7 | A6 | A5
+      CLEAR_WORD32(a, 5, 5);
+
+      //Compute A = A + T + (T << 31)
+      MPI_CHECK(mpiAdd(a, a, &t));
+      MPI_CHECK(mpiShiftLeft(&t, 31));
+      MPI_CHECK(mpiAdd(a, a, &t));
+
+      //Check for end condition
+   } while(mpiComp(a, p) > 0);
+
+end:
+   //Release multiple precision integers
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp160r2 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp160r2Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 40 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 24 / MPI_INT_SIZE));
+
+   //Perform modular reduction
+   do
+   {
+      //Compute T = A9 | A8 | A7 | A6 | A5 | 0
+      CLEAR_WORD32(&t, 0, 1);
+      COPY_WORD32(&t, 1, a, 5, 5);
+
+      //Clear A9 | A8 | A7 | A6 | A5
+      CLEAR_WORD32(a, 5, 5);
+
+      //Compute A = A + T
+      MPI_CHECK(mpiAdd(a, a, &t));
+      //Compute T = T >> 32
+      MPI_CHECK(mpiShiftRight(&t, 32));
+      //Compute A = A + (21389 * T)
+      MPI_CHECK(mpiMulInt(&t, &t, 21389));
+      MPI_CHECK(mpiAdd(a, a, &t));
+
+      //Check for end condition
+   } while(mpiComp(a, p) > 0);
+
+end:
+   //Release multiple precision integers
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp192k1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp192k1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 48 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 28 / MPI_INT_SIZE));
+
+   //Perform modular reduction
+   do
+   {
+      //Compute T = A11 | A10 | A9 | A8 | A7 | A6 | 0
+      CLEAR_WORD32(&t, 0, 1);
+      COPY_WORD32(&t, 1, a, 6, 6);
+
+      //Clear A11 | A10 | A9 | A8 | A7 | A6
+      CLEAR_WORD32(a, 6, 6);
+
+      //Compute A = A + T
+      MPI_CHECK(mpiAdd(a, a, &t));
+      //Compute T = T >> 32
+      MPI_CHECK(mpiShiftRight(&t, 32));
+      //Compute A = A + (4553 * T)
+      MPI_CHECK(mpiMulInt(&t, &t, 4553));
+      MPI_CHECK(mpiAdd(a, a, &t));
+
+      //Check for end condition
+   } while(mpiComp(a, p) > 0);
+
+end:
+   //Release multiple precision integers
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp192r1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp192r1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi s;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&s);
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 48 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&s, 24 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 24 / MPI_INT_SIZE));
+
+   //Compute T = A5 | A4 | A3 | A2 | A1 | A0
+   COPY_WORD32(&t, 0, a, 0, 6);
+
+   //Compute S1 = 0 | 0 | A7 | A6 | A7 | A6
+   COPY_WORD32(&s, 0, a, 6, 2);
+   COPY_WORD32(&s, 2, a, 6, 2);
+   CLEAR_WORD32(&s, 4, 2);
+   //Compute T = T + S1
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S2 = A9 | A8 | A9 | A8 | 0 | 0
+   CLEAR_WORD32(&s, 0, 2);
+   COPY_WORD32(&s, 2, a, 8, 2);
+   COPY_WORD32(&s, 4, a, 8, 2);
+   //Compute T = T + S2
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S3 = A11 | A10 | A11 | A10 | A11 | A10
+   COPY_WORD32(&s, 0, a, 10, 2);
+   COPY_WORD32(&s, 2, a, 10, 2);
+   COPY_WORD32(&s, 4, a, 10, 2);
+   //Compute T = T + S3
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute (T + S1 + S2 + S3) mod p
+   while(mpiComp(&t, p) >= 0)
+   {
+       MPI_CHECK(mpiSub(&t, &t, p));
+   }
+
+   //Save result
+   MPI_CHECK(mpiCopy(a, &t));
+
+end:
+   //Release multiple precision integers
+   mpiFree(&s);
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp224k1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp224k1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 56 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 32 / MPI_INT_SIZE));
+
+   //Perform modular reduction
+   do
+   {
+      //Compute T = A13 | A12 | A11 | A10 | A9 | A8 | A7 | 0
+      CLEAR_WORD32(&t, 0, 1);
+      COPY_WORD32(&t, 1, a, 7, 7);
+
+      //Clear A13 | A12 | A11 | A10 | A9 | A8 | A7
+      CLEAR_WORD32(a, 7, 7);
+
+      //Compute A = A + T
+      MPI_CHECK(mpiAdd(a, a, &t));
+      //Compute T = T >> 32
+      MPI_CHECK(mpiShiftRight(&t, 32));
+      //Compute A = A + (6803 * T)
+      MPI_CHECK(mpiMulInt(&t, &t, 6803));
+      MPI_CHECK(mpiAdd(a, a, &t));
+
+      //Check for end condition
+   } while(mpiComp(a, p) > 0);
+
+end:
+   //Release multiple precision integers
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp224r1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp224r1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi s;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&s);
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 56 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&s, 28 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 28 / MPI_INT_SIZE));
+
+   //Compute T = A6 | A5 | A4 | A3 | A2 | A1 | A0
+   COPY_WORD32(&t, 0, a, 0, 7);
+
+   //Compute S1 = A10 | A9 | A8 | A7 | 0 | 0 | 0
+   CLEAR_WORD32(&s, 0, 3);
+   COPY_WORD32(&s, 3, a, 7, 4);
+   //Compute T = T + S1
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S2 = 0 | A13 | A12 | A11 | 0 | 0 | 0
+   CLEAR_WORD32(&s, 0, 3);
+   COPY_WORD32(&s, 3, a, 11, 3);
+   CLEAR_WORD32(&s, 6, 1);
+   //Compute T = T + S2
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute D1 = A13 | A12 | A11 | A10 | A9 | A8 | A7
+   COPY_WORD32(&s, 0, a, 7, 7);
+   //Compute T = T - D1
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute D2 = 0 | 0 | 0 | 0 | A13 | A12 | A11
+   COPY_WORD32(&s, 0, a, 11, 3);
+   CLEAR_WORD32(&s, 3, 4);
+   //Compute T = T - D2
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute (T + S1 + S2 - D1 - D2) mod p
+   while(mpiComp(&t, p) >= 0)
+   {
+       MPI_CHECK(mpiSub(&t, &t, p));
+   }
+
+   while(mpiCompInt(&t, 0) < 0)
+   {
+       MPI_CHECK(mpiAdd(&t, &t, p));
+   }
+
+   //Save result
+   MPI_CHECK(mpiCopy(a, &t));
+
+end:
+   //Release multiple precision integers
+   mpiFree(&s);
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp256k1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp256k1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 64 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 36 / MPI_INT_SIZE));
+
+   //Perform modular reduction
+   do
+   {
+      //Compute T = A15 | A14 | A13 | A12 | A11 | A10 | A9 | A8 | 0
+      CLEAR_WORD32(&t, 0, 1);
+      COPY_WORD32(&t, 1, a, 8, 8);
+
+      //Clear A15 | A14 | A13 | A12 | A11 | A10 | A9 | A8
+      CLEAR_WORD32(a, 8, 8);
+
+      //Compute A = A + T
+      MPI_CHECK(mpiAdd(a, a, &t));
+      //Compute T = T >> 32
+      MPI_CHECK(mpiShiftRight(&t, 32));
+      //Compute A = A + (977 * T)
+      MPI_CHECK(mpiMulInt(&t, &t, 977));
+      MPI_CHECK(mpiAdd(a, a, &t));
+
+      //Check for end condition
+   } while(mpiComp(a, p) > 0);
+
+end:
+   //Release multiple precision integers
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp256r1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp256r1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi s;
+   Mpi t;
+   Mpi b;
+
+   //Initialize multiple precision integers
+   mpiInit(&s);
+   mpiInit(&t);
+   mpiInit(&b);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 64 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&s, 32 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 32 / MPI_INT_SIZE));
+
+   //Compute T = A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0
+   COPY_WORD32(&t, 0, a, 0, 8);
+
+   //Compute S1 = A15 | A14 | A13 | A12 | A11 | 0 | 0 | 0
+   CLEAR_WORD32(&s, 0, 3);
+   COPY_WORD32(&s, 3, a, 11, 5);
+   //Compute T = T + 2 * S1
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S2 = 0 | A15 | A14 | A13 | A12 | 0 | 0 | 0
+   CLEAR_WORD32(&s, 0, 3);
+   COPY_WORD32(&s, 3, a, 12, 4);
+   CLEAR_WORD32(&s, 7, 1);
+   //Compute T = T + 2 * S2
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S3 = A15 | A14 | 0 | 0 | 0 | A10 | A9 | A8
+   COPY_WORD32(&s, 0, a, 8, 3);
+   CLEAR_WORD32(&s, 3, 3);
+   COPY_WORD32(&s, 6, a, 14, 2);
+   //Compute T = T + S3
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S4 = A8 | A13 | A15 | A14 | A13 | A11 | A10 | A9
+   COPY_WORD32(&s, 0, a, 9, 3);
+   COPY_WORD32(&s, 3, a, 13, 3);
+   COPY_WORD32(&s, 6, a, 13, 1);
+   COPY_WORD32(&s, 7, a, 8, 1);
+   //Compute T = T + S4
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute D1 = A10 | A8 | 0 | 0 | 0 | A13 | A12 | A11
+   COPY_WORD32(&s, 0, a, 11, 3);
+   CLEAR_WORD32(&s, 3, 3);
+   COPY_WORD32(&s, 6, a, 8, 1);
+   COPY_WORD32(&s, 7, a, 10, 1);
+   //Compute T = T - D1
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute D2 = A11 | A9 | 0 | 0 | A15 | A14 | A13 | A12
+   COPY_WORD32(&s, 0, a, 12, 4);
+   CLEAR_WORD32(&s, 4, 2);
+   COPY_WORD32(&s, 6, a, 9, 1);
+   COPY_WORD32(&s, 7, a, 11, 1);
+   //Compute T = T - D2
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute D3 = A12 | 0 | A10 | A9 | A8 | A15 | A14 | A13
+   COPY_WORD32(&s, 0, a, 13, 3);
+   COPY_WORD32(&s, 3, a, 8, 3);
+   CLEAR_WORD32(&s, 6, 1);
+   COPY_WORD32(&s, 7, a, 12, 1);
+   //Compute T = T - D3
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute D4 = A13 | 0 | A11 | A10 | A9 | 0 | A15 | A14
+   COPY_WORD32(&s, 0, a, 14, 2);
+   CLEAR_WORD32(&s, 2, 1);
+   COPY_WORD32(&s, 3, a, 9, 3);
+   CLEAR_WORD32(&s, 6, 1);
+   COPY_WORD32(&s, 7, a, 13, 1);
+   //Compute T = T - D4
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute (T + 2 * S1 + 2 * S2 + S3 + S4 - D1 - D2 - D3 - D4) mod p
+   while(mpiComp(&t, p) >= 0)
+   {
+       MPI_CHECK(mpiSub(&t, &t, p));
+   }
+
+   while(mpiCompInt(&t, 0) < 0)
+   {
+       MPI_CHECK(mpiAdd(&t, &t, p));
+   }
+
+   //Save result
+   MPI_CHECK(mpiCopy(a, &t));
+
+end:
+   //Release multiple precision integers
+   mpiFree(&s);
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp384r1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp384r1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi s;
+   Mpi t;
+
+   //Initialize multiple precision integers
+   mpiInit(&s);
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 96 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&s, 48 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 48 / MPI_INT_SIZE));
+
+   //Compute T = A11 | A10 | A9 | A8 | A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0
+   COPY_WORD32(&t, 0, a, 0, 12);
+
+   //Compute S1 = 0 | 0 | 0 | 0 | 0 | A23 | A22 | A21 | 0 | 0 | 0 | 0
+   CLEAR_WORD32(&s, 0, 4);
+   COPY_WORD32(&s, 4, a, 21, 3);
+   CLEAR_WORD32(&s, 7, 5);
+   //Compute T = T + 2 * S1
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S2 = A23 | A22 | A21 | A20 | A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12
+   COPY_WORD32(&s, 0, a, 12, 12);
+   //Compute T = T + S2
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S3 = A20 | A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12 | A23| A22 | A21
+   COPY_WORD32(&s, 0, a, 21, 3);
+   COPY_WORD32(&s, 3, a, 12, 9);
+   //Compute T = T + S3
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S4 = A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12 | A20 | 0 | A23 | 0
+   CLEAR_WORD32(&s, 0, 1);
+   COPY_WORD32(&s, 1, a, 23, 1);
+   CLEAR_WORD32(&s, 2, 1);
+   COPY_WORD32(&s, 3, a, 20, 1);
+   COPY_WORD32(&s, 4, a, 12, 8);
+   //Compute T = T + S4
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S5 = 0 | 0 | 0 | 0 | A23 | A22 | A21 | A20 | 0 | 0 | 0 | 0
+   CLEAR_WORD32(&s, 0, 4);
+   COPY_WORD32(&s, 4, a, 20, 4);
+   CLEAR_WORD32(&s, 8, 4);
+   //Compute T = T + S5
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute S6 = 0 | 0 | 0 | 0 | 0 | 0 | A23 | A22 | A21 | 0 | 0 | A20
+   COPY_WORD32(&s, 0, a, 20, 1);
+   CLEAR_WORD32(&s, 1, 2);
+   COPY_WORD32(&s, 3, a, 21, 3);
+   CLEAR_WORD32(&s, 6, 6);
+   //Compute T = T + S6
+   MPI_CHECK(mpiAdd(&t, &t, &s));
+
+   //Compute D1 = A22 | A21 | A20 | A19 | A18 | A17 | A16 | A15 | A14 | A13 | A12 | A23
+   COPY_WORD32(&s, 0, a, 23, 1);
+   COPY_WORD32(&s, 1, a, 12, 11);
+   //Compute T = T - D1
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute D2 = 0 | 0 | 0 | 0 | 0 | 0 | 0 | A23 | A22 | A21 | A20 | 0
+   CLEAR_WORD32(&s, 0, 1);
+   COPY_WORD32(&s, 1, a, 20, 4);
+   CLEAR_WORD32(&s, 5, 7);
+   //Compute T = T - D2
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute D3 = 0 | 0 | 0 | 0 | 0 | 0 | 0 | A23 | A23 | 0 | 0 | 0
+   CLEAR_WORD32(&s, 0, 3);
+   COPY_WORD32(&s, 3, a, 23, 1);
+   COPY_WORD32(&s, 4, a, 23, 1);
+   CLEAR_WORD32(&s, 5, 7);
+   //Compute T = T - D3
+   MPI_CHECK(mpiSub(&t, &t, &s));
+
+   //Compute (T + 2 * S1 + S2 + S3 + S4 + S5 + S6 - D1 - D2 - D3) mod p
+   while(mpiComp(&t, p) >= 0)
+   {
+       MPI_CHECK(mpiSub(&t, &t, p));
+   }
+
+   while(mpiCompInt(&t, 0) < 0)
+   {
+       MPI_CHECK(mpiAdd(&t, &t, p));
+   }
+
+   //Save result
+   MPI_CHECK(mpiCopy(a, &t));
+
+end:
+   //Release multiple precision integers
+   mpiFree(&s);
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Fast modular reduction (secp521r1 curve)
+ * @param[in,out] a This function accept an integer less than p^2 as
+ *   input and return (a mod p) as output
+ * @param[in] p Prime modulus
+ **/
+
+error_t secp521r1Mod(Mpi *a, const Mpi *p)
+{
+   error_t error;
+   Mpi t;
+
+   //Initialize multiple precision integer
+   mpiInit(&t);
+
+   //Ajust the size of the integers
+   MPI_CHECK(mpiGrow(a, 132 / MPI_INT_SIZE));
+   MPI_CHECK(mpiGrow(&t, 68 / MPI_INT_SIZE));
+
+   //Compute A0
+   COPY_WORD32(&t, 0, a, 0, 17);
+   t.data[16] &= 0x000001FF;
+
+   //Compute A1
+   MPI_CHECK(mpiShiftRight(a, 521));
+
+   //Compute A0 + A1
+   MPI_CHECK(mpiAdd(a, a, &t));
+
+   //Compute (A0 + A1) mod p
+   while(mpiComp(a, p) >= 0)
+   {
+       MPI_CHECK(mpiSub(a, a, p));
+   }
+
+end:
+   //Release multiple precision integer
+   mpiFree(&t);
+
+   //Return status code
+   return error;
+}
+
+
+/**
+ * @brief Get the elliptic curve that matches the specified OID
+ * @param[in] oid Object identifier
+ * @param[in] length OID length
+ * @return Elliptic curve domain parameters
+ **/
+
+const EcCurveInfo *ecGetCurveInfo(const uint8_t *oid, size_t length)
+{
+   //secp112r1 elliptic curve?
+   if(!oidComp(oid, length, SECP112R1_OID, sizeof(SECP112R1_OID)))
+      return SECP112R1_CURVE;
+   //secp112r2 elliptic curve?
+   if(!oidComp(oid, length, SECP112R2_OID, sizeof(SECP112R2_OID)))
+      return SECP112R2_CURVE;
+   //secp128r1 elliptic curve?
+   if(!oidComp(oid, length, SECP128R1_OID, sizeof(SECP128R1_OID)))
+      return SECP128R1_CURVE;
+   //secp128r2 elliptic curve?
+   if(!oidComp(oid, length, SECP128R2_OID, sizeof(SECP128R2_OID)))
+      return SECP128R2_CURVE;
+   //secp160k1 elliptic curve?
+   if(!oidComp(oid, length, SECP160K1_OID, sizeof(SECP160K1_OID)))
+      return SECP160K1_CURVE;
+   //secp160r1 elliptic curve?
+   else if(!oidComp(oid, length, SECP160R1_OID, sizeof(SECP160R1_OID)))
+      return SECP160R1_CURVE;
+   //secp160r2 elliptic curve?
+   else if(!oidComp(oid, length, SECP160R2_OID, sizeof(SECP160R2_OID)))
+      return SECP160R2_CURVE;
+   //secp192k1 elliptic curve?
+   else if(!oidComp(oid, length, SECP192K1_OID, sizeof(SECP192K1_OID)))
+      return SECP192K1_CURVE;
+   //secp192r1 elliptic curve?
+   else if(!oidComp(oid, length, SECP192R1_OID, sizeof(SECP192R1_OID)))
+      return SECP192R1_CURVE;
+   //secp224k1 elliptic curve?
+   else if(!oidComp(oid, length, SECP224K1_OID, sizeof(SECP224K1_OID)))
+      return SECP224K1_CURVE;
+   //secp224r1 elliptic curve?
+   else if(!oidComp(oid, length, SECP224R1_OID, sizeof(SECP224R1_OID)))
+      return SECP224R1_CURVE;
+   //secp256k1 elliptic curve?
+   else if(!oidComp(oid, length, SECP256K1_OID, sizeof(SECP256K1_OID)))
+      return SECP256K1_CURVE;
+   //secp256r1 elliptic curve?
+   else if(!oidComp(oid, length, SECP256R1_OID, sizeof(SECP256R1_OID)))
+      return SECP256R1_CURVE;
+   //secp384r1 elliptic curve?
+   else if(!oidComp(oid, length, SECP384R1_OID, sizeof(SECP384R1_OID)))
+      return SECP384R1_CURVE;
+   //secp521r1 elliptic curve?
+   else if(!oidComp(oid, length, SECP521R1_OID, sizeof(SECP521R1_OID)))
+      return SECP521R1_CURVE;
+   //brainpoolP160r1 elliptic curve?
+   else if(!oidComp(oid, length, BRAINPOOLP160R1_OID, sizeof(BRAINPOOLP160R1_OID)))
+      return BRAINPOOLP160R1_CURVE;
+   //brainpoolP192r1 elliptic curve?
+   else if(!oidComp(oid, length, BRAINPOOLP192R1_OID, sizeof(BRAINPOOLP192R1_OID)))
+      return BRAINPOOLP192R1_CURVE;
+   //brainpoolP224r1 elliptic curve?
+   else if(!oidComp(oid, length, BRAINPOOLP224R1_OID, sizeof(BRAINPOOLP224R1_OID)))
+      return BRAINPOOLP224R1_CURVE;
+   //brainpoolP256r1 elliptic curve?
+   else if(!oidComp(oid, length, BRAINPOOLP256R1_OID, sizeof(BRAINPOOLP256R1_OID)))
+      return BRAINPOOLP256R1_CURVE;
+   //brainpoolP320r1 elliptic curve?
+   else if(!oidComp(oid, length, BRAINPOOLP320R1_OID, sizeof(BRAINPOOLP320R1_OID)))
+      return BRAINPOOLP320R1_CURVE;
+   //brainpoolP384r1 elliptic curve?
+   else if(!oidComp(oid, length, BRAINPOOLP384R1_OID, sizeof(BRAINPOOLP384R1_OID)))
+      return BRAINPOOLP384R1_CURVE;
+   //brainpoolP512r1 elliptic curve?
+   else if(!oidComp(oid, length, BRAINPOOLP512R1_OID, sizeof(BRAINPOOLP512R1_OID)))
+      return BRAINPOOLP512R1_CURVE;
+   //Unknown identifier?
+   else
+      return NULL;
+}
+
+#endif
+