Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dsa.c Source File

dsa.c

Go to the documentation of this file.
00001 /**
00002  * @file dsa.c
00003  * @brief DSA (Digital Signature Algorithm)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneCrypto Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @section Description
00026  *
00027  * The Digital Signature Algorithm (DSA) is a an algorithm developed by the
00028  * NSA to generate a digital signature for the authentication of electronic
00029  * documents. Refer to FIPS 186-3 for more details
00030  *
00031  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00032  * @version 1.7.6
00033  **/
00034 
00035 //Switch to the appropriate trace level
00036 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
00037 
00038 //Dependencies
00039 #include <stdlib.h>
00040 #include "crypto.h"
00041 #include "dsa.h"
00042 #include "mpi.h"
00043 #include "asn1.h"
00044 #include "debug.h"
00045 
00046 //Check crypto library configuration
00047 #if (DSA_SUPPORT == ENABLED)
00048 
00049 //DSA OID (1.2.840.10040.4.1)
00050 const uint8_t DSA_OID[7] = {0x2A, 0x86, 0x48, 0xCE, 0x38, 0x04, 0x01};
00051 //DSA with SHA-1 OID (1.2.840.10040.4.3)
00052 const uint8_t DSA_WITH_SHA1_OID[7] = {0x2A, 0x86, 0x48, 0xCE, 0x38, 0x04, 0x03};
00053 //DSA with SHA-224 OID (2.16.840.1.101.3.4.3.1)
00054 const uint8_t DSA_WITH_SHA224_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x01};
00055 //DSA with SHA-256 OID (2.16.840.1.101.3.4.3.2)
00056 const uint8_t DSA_WITH_SHA256_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x02};
00057 //DSA with SHA-384 OID (2.16.840.1.101.3.4.3.3)
00058 const uint8_t DSA_WITH_SHA384_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x03};
00059 //DSA with SHA-512 OID (2.16.840.1.101.3.4.3.4)
00060 const uint8_t DSA_WITH_SHA512_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x04};
00061 //DSA with SHA-3-224 OID (2.16.840.1.101.3.4.3.5)
00062 const uint8_t DSA_WITH_SHA3_224_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x05};
00063 //DSA with SHA-3-256 OID (2.16.840.1.101.3.4.3.6)
00064 const uint8_t DSA_WITH_SHA3_256_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x06};
00065 //DSA with SHA-3-384 OID (2.16.840.1.101.3.4.3.7)
00066 const uint8_t DSA_WITH_SHA3_384_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x07};
00067 //DSA with SHA-3-512 OID (2.16.840.1.101.3.4.3.8)
00068 const uint8_t DSA_WITH_SHA3_512_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x08};
00069 
00070 
00071 /**
00072  * @brief Initialize a DSA public key
00073  * @param[in] key Pointer to the DSA public key to initialize
00074  **/
00075 
00076 void dsaInitPublicKey(DsaPublicKey *key)
00077 {
00078    //Initialize multiple precision integers
00079    mpiInit(&key->p);
00080    mpiInit(&key->q);
00081    mpiInit(&key->g);
00082    mpiInit(&key->y);
00083 }
00084 
00085 
00086 /**
00087  * @brief Release a DSA public key
00088  * @param[in] key Pointer to the DSA public key to free
00089  **/
00090 
00091 void dsaFreePublicKey(DsaPublicKey *key)
00092 {
00093    //Free multiple precision integers
00094    mpiFree(&key->p);
00095    mpiFree(&key->q);
00096    mpiFree(&key->g);
00097    mpiFree(&key->y);
00098 }
00099 
00100 
00101 /**
00102  * @brief Initialize a DSA private key
00103  * @param[in] key Pointer to the DSA private key to initialize
00104  **/
00105 
00106 void dsaInitPrivateKey(DsaPrivateKey *key)
00107 {
00108    //Initialize multiple precision integers
00109    mpiInit(&key->p);
00110    mpiInit(&key->q);
00111    mpiInit(&key->g);
00112    mpiInit(&key->x);
00113 }
00114 
00115 
00116 /**
00117  * @brief Release a DSA private key
00118  * @param[in] key Pointer to the DSA public key to free
00119  **/
00120 
00121 void dsaFreePrivateKey(DsaPrivateKey *key)
00122 {
00123    //Free multiple precision integers
00124    mpiFree(&key->p);
00125    mpiFree(&key->q);
00126    mpiFree(&key->g);
00127    mpiFree(&key->x);
00128 }
00129 
00130 
00131 /**
00132  * @brief Initialize a DSA signature
00133  * @param[in] signature Pointer to the DSA signature to initialize
00134  **/
00135 
00136 void dsaInitSignature(DsaSignature *signature)
00137 {
00138    //Initialize multiple precision integers
00139    mpiInit(&signature->r);
00140    mpiInit(&signature->s);
00141 }
00142 
00143 
00144 /**
00145  * @brief Release a DSA signature
00146  * @param[in] signature Pointer to the DSA signature to free
00147  **/
00148 
00149 void dsaFreeSignature(DsaSignature *signature)
00150 {
00151    //Release multiple precision integers
00152    mpiFree(&signature->r);
00153    mpiFree(&signature->s);
00154 }
00155 
00156 
00157 /**
00158  * @brief Encode DSA signature using ASN.1
00159  * @param[in] signature (R, S) integer pair
00160  * @param[out] data Pointer to the buffer where to store the resulting ASN.1 structure
00161  * @param[out] length Length of the ASN.1 structure
00162  * @return Error code
00163  **/
00164 
00165 error_t dsaWriteSignature(const DsaSignature *signature, uint8_t *data, size_t *length)
00166 {
00167    error_t error;
00168    size_t k;
00169    size_t n;
00170    size_t rLen;
00171    size_t sLen;
00172    Asn1Tag tag;
00173 
00174    //Debug message
00175    TRACE_DEBUG("Writing DSA signature...\r\n");
00176 
00177    //Dump (R, S) integer pair
00178    TRACE_DEBUG("  r:\r\n");
00179    TRACE_DEBUG_MPI("    ", &signature->r);
00180    TRACE_DEBUG("  s:\r\n");
00181    TRACE_DEBUG_MPI("    ", &signature->s);
00182 
00183    //Calculate the length of R
00184    rLen = mpiGetByteLength(&signature->r);
00185    //Calculate the length of S
00186    sLen = mpiGetByteLength(&signature->s);
00187 
00188    //Make sure the (R, S) integer pair is valid
00189    if(rLen == 0 || sLen == 0)
00190       return ERROR_INVALID_LENGTH;
00191 
00192    //R and S are always encoded in the smallest possible number of octets
00193    if(mpiGetBitValue(&signature->r, (rLen * 8) - 1))
00194       rLen++;
00195    if(mpiGetBitValue(&signature->s, (sLen * 8) - 1))
00196       sLen++;
00197 
00198    //The first pass computes the length of the ASN.1 sequence
00199    n = 0;
00200 
00201    //The parameter R is encapsulated within an ASN.1 structure
00202    tag.constructed = FALSE;
00203    tag.objClass = ASN1_CLASS_UNIVERSAL;
00204    tag.objType = ASN1_TYPE_INTEGER;
00205    tag.length = rLen;
00206    tag.value = NULL;
00207 
00208    //Compute the length of the corresponding ASN.1 structure
00209    error = asn1WriteTag(&tag, FALSE, NULL, NULL);
00210    //Any error to report?
00211    if(error)
00212       return error;
00213 
00214    //Update the length of the ASN.1 sequence
00215    n += tag.totalLength;
00216 
00217    //The parameter S is encapsulated within an ASN.1 structure
00218    tag.constructed = FALSE;
00219    tag.objClass = ASN1_CLASS_UNIVERSAL;
00220    tag.objType = ASN1_TYPE_INTEGER;
00221    tag.length = sLen;
00222    tag.value = NULL;
00223 
00224    //Compute the length of the corresponding ASN.1 structure
00225    error = asn1WriteTag(&tag, FALSE, NULL, NULL);
00226    //Any error to report?
00227    if(error)
00228       return error;
00229 
00230    //Update the length of the ASN.1 sequence
00231    n += tag.totalLength;
00232 
00233    //The second pass encodes the ASN.1 structure
00234    k = 0;
00235 
00236    //The (R, S) integer pair is encapsulated within a sequence
00237    tag.constructed = TRUE;
00238    tag.objClass = ASN1_CLASS_UNIVERSAL;
00239    tag.objType = ASN1_TYPE_SEQUENCE;
00240    tag.length = n;
00241    tag.value = NULL;
00242 
00243    //Write the corresponding ASN.1 tag
00244    error = asn1WriteTag(&tag, FALSE, data + k, &n);
00245    //Any error to report?
00246    if(error)
00247       return error;
00248 
00249    //Advance write pointer
00250    k += n;
00251 
00252    //Encode the parameter R using ASN.1
00253    tag.constructed = FALSE;
00254    tag.objClass = ASN1_CLASS_UNIVERSAL;
00255    tag.objType = ASN1_TYPE_INTEGER;
00256    tag.length = rLen;
00257    tag.value = NULL;
00258 
00259    //Write the corresponding ASN.1 tag
00260    error = asn1WriteTag(&tag, FALSE, data + k, &n);
00261    //Any error to report?
00262    if(error)
00263       return error;
00264 
00265    //Advance write pointer
00266    k += n;
00267 
00268    //Convert R to an octet string
00269    error = mpiWriteRaw(&signature->r, data + k, rLen);
00270    //Any error to report?
00271    if(error)
00272       return error;
00273 
00274    //Advance write pointer
00275    k += rLen;
00276 
00277    //Encode the parameter S using ASN.1
00278    tag.constructed = FALSE;
00279    tag.objClass = ASN1_CLASS_UNIVERSAL;
00280    tag.objType = ASN1_TYPE_INTEGER;
00281    tag.length = sLen;
00282    tag.value = NULL;
00283 
00284    //Write the corresponding ASN.1 tag
00285    error = asn1WriteTag(&tag, FALSE, data + k, &n);
00286    //Any error to report?
00287    if(error)
00288       return error;
00289 
00290    //Advance write pointer
00291    k += n;
00292 
00293    //Convert S to an octet string
00294    error = mpiWriteRaw(&signature->s, data + k, sLen);
00295    //Any error to report?
00296    if(error)
00297       return error;
00298 
00299    //Advance write pointer
00300    k += sLen;
00301 
00302    //Dump DSA signature
00303    TRACE_DEBUG("  signature:\r\n");
00304    TRACE_DEBUG_ARRAY("    ", data, k);
00305 
00306    //Total length of the ASN.1 structure
00307    *length = k;
00308    //Successful processing
00309    return NO_ERROR;
00310 }
00311 
00312 
00313 /**
00314  * @brief Read an ASN.1 encoded DSA signature
00315  * @param[in] data Pointer to the ASN.1 structure to decode
00316  * @param[in] length Length of the ASN.1 structure
00317  * @param[out] signature (R, S) integer pair
00318  * @return Error code
00319  **/
00320 
00321 error_t dsaReadSignature(const uint8_t *data, size_t length, DsaSignature *signature)
00322 {
00323    error_t error;
00324    Asn1Tag tag;
00325 
00326    //Debug message
00327    TRACE_DEBUG("Reading DSA signature...\r\n");
00328 
00329    //Dump DSA signature
00330    TRACE_DEBUG("  signature:\r\n");
00331    TRACE_DEBUG_ARRAY("    ", data, length);
00332 
00333    //Start of exception handling block
00334    do
00335    {
00336       //Display ASN.1 structure
00337       error = asn1DumpObject(data, length, 0);
00338       //Any error to report?
00339       if(error)
00340          break;
00341 
00342       //Read the contents of the ASN.1 structure
00343       error = asn1ReadTag(data, length, &tag);
00344       //Failed to decode ASN.1 tag?
00345       if(error)
00346          break;
00347 
00348       //Enforce encoding, class and type
00349       error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
00350       //The tag does not match the criteria?
00351       if(error)
00352          break;
00353 
00354       //Point to the first field
00355       data = tag.value;
00356       length = tag.length;
00357 
00358       //Read the parameter R
00359       error = asn1ReadTag(data, length, &tag);
00360       //Failed to decode ASN.1 tag?
00361       if(error)
00362          break;
00363 
00364       //Enforce encoding, class and type
00365       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00366       //The tag does not match the criteria?
00367       if(error)
00368          break;
00369 
00370       //Convert the octet string to a multiple precision integer
00371       error = mpiReadRaw(&signature->r, tag.value, tag.length);
00372       //Any error to report?
00373       if(error)
00374          break;
00375 
00376       //Point to the next field
00377       data += tag.totalLength;
00378       length -= tag.totalLength;
00379 
00380       //Read the parameter S
00381       error = asn1ReadTag(data, length, &tag);
00382       //Failed to decode ASN.1 tag?
00383       if(error)
00384          break;
00385 
00386       //Enforce encoding, class and type
00387       error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER);
00388       //The tag does not match the criteria?
00389       if(error)
00390          break;
00391 
00392       //Convert the octet string to a multiple precision integer
00393       error = mpiReadRaw(&signature->s, tag.value, tag.length);
00394       //Any error to report?
00395       if(error)
00396          break;
00397 
00398       //Dump (R, S) integer pair
00399       TRACE_DEBUG("  r:\r\n");
00400       TRACE_DEBUG_MPI("    ", &signature->r);
00401       TRACE_DEBUG("  s:\r\n");
00402       TRACE_DEBUG_MPI("    ", &signature->s);
00403 
00404       //End of exception handling block
00405    } while(0);
00406 
00407    //Clean up side effects if necessary
00408    if(error)
00409       dsaFreeSignature(signature);
00410 
00411    //Return status code
00412    return error;
00413 }
00414 
00415 
00416 /**
00417  * @brief DSA signature generation
00418  * @param[in] prngAlgo PRNG algorithm
00419  * @param[in] prngContext Pointer to the PRNG context
00420  * @param[in] key Signer's DSA private key
00421  * @param[in] digest Digest of the message to be signed
00422  * @param[in] digestLength Length in octets of the digest
00423  * @param[out] signature (R, S) integer pair
00424  * @return Error code
00425  **/
00426 
00427 error_t dsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
00428    const DsaPrivateKey *key, const uint8_t *digest, size_t digestLength,
00429    DsaSignature *signature)
00430 {
00431    error_t error;
00432    uint_t n;
00433    Mpi k;
00434    Mpi z;
00435 
00436    //Check parameters
00437    if(key == NULL || digest == NULL || signature == NULL)
00438       return ERROR_INVALID_PARAMETER;
00439 
00440    //Debug message
00441    TRACE_DEBUG("DSA signature generation...\r\n");
00442    TRACE_DEBUG("  p:\r\n");
00443    TRACE_DEBUG_MPI("    ", &key->p);
00444    TRACE_DEBUG("  q:\r\n");
00445    TRACE_DEBUG_MPI("    ", &key->q);
00446    TRACE_DEBUG("  g:\r\n");
00447    TRACE_DEBUG_MPI("    ", &key->g);
00448    TRACE_DEBUG("  x:\r\n");
00449    TRACE_DEBUG_MPI("    ", &key->x);
00450    TRACE_DEBUG("  digest:\r\n");
00451    TRACE_DEBUG_ARRAY("    ", digest, digestLength);
00452 
00453    //Initialize multiple precision integers
00454    mpiInit(&k);
00455    mpiInit(&z);
00456 
00457    //Let N be the bit length of q
00458    n = mpiGetBitLength(&key->q);
00459 
00460    //Generated a pseudorandom number
00461    MPI_CHECK(mpiRand(&k, n, prngAlgo, prngContext));
00462 
00463    //Make sure that 0 < k < q
00464    if(mpiComp(&k, &key->q) >= 0)
00465       mpiShiftRight(&k, 1);
00466 
00467    //Debug message
00468    TRACE_DEBUG("  k:\r\n");
00469    TRACE_DEBUG_MPI("    ", &k);
00470 
00471    //Compute N = MIN(N, outlen)
00472    n = MIN(n, digestLength * 8);
00473 
00474    //Convert the digest to a multiple precision integer
00475    MPI_CHECK(mpiReadRaw(&z, digest, (n + 7) / 8));
00476 
00477    //Keep the leftmost N bits of the hash value
00478    if(n % 8)
00479    {
00480       MPI_CHECK(mpiShiftRight(&z, 8 - (n % 8)));
00481    }
00482 
00483    //Debug message
00484    TRACE_DEBUG("  z:\r\n");
00485    TRACE_DEBUG_MPI("    ", &z);
00486 
00487    //Compute r = (g ^ k mod p) mod q
00488    MPI_CHECK(mpiExpMod(&signature->r, &key->g, &k, &key->p));
00489    MPI_CHECK(mpiMod(&signature->r, &signature->r, &key->q));
00490 
00491    //Compute k ^ -1 mod q
00492    MPI_CHECK(mpiInvMod(&k, &k, &key->q));
00493 
00494    //Compute s = k ^ -1 * (z + x * r) mod q
00495    MPI_CHECK(mpiMul(&signature->s, &key->x, &signature->r));
00496    MPI_CHECK(mpiAdd(&signature->s, &signature->s, &z));
00497    MPI_CHECK(mpiMod(&signature->s, &signature->s, &key->q));
00498    MPI_CHECK(mpiMulMod(&signature->s, &signature->s, &k, &key->q));
00499 
00500    //Dump DSA signature
00501    TRACE_DEBUG("  r:\r\n");
00502    TRACE_DEBUG_MPI("    ", &signature->r);
00503    TRACE_DEBUG("  s:\r\n");
00504    TRACE_DEBUG_MPI("    ", &signature->s);
00505 
00506 end:
00507    //Release multiple precision integers
00508    mpiFree(&k);
00509    mpiFree(&z);
00510 
00511    //Clean up side effects if necessary
00512    if(error)
00513    {
00514       //Release (R, S) integer pair
00515       mpiFree(&signature->r);
00516       mpiFree(&signature->r);
00517    }
00518 
00519    //Return status code
00520    return error;
00521 }
00522 
00523 
00524 /**
00525  * @brief DSA signature verification
00526  * @param[in] key Signer's DSA public key
00527  * @param[in] digest Digest of the message whose signature is to be verified
00528  * @param[in] digestLength Length in octets of the digest
00529  * @param[in] signature (R, S) integer pair
00530  * @return Error code
00531  **/
00532 
00533 error_t dsaVerifySignature(const DsaPublicKey *key,
00534    const uint8_t *digest, size_t digestLength, const DsaSignature *signature)
00535 {
00536    error_t error;
00537    uint_t n;
00538    Mpi w;
00539    Mpi z;
00540    Mpi u1;
00541    Mpi u2;
00542    Mpi v;
00543 
00544    //Check parameters
00545    if(key == NULL || digest == NULL || signature == NULL)
00546       return ERROR_INVALID_PARAMETER;
00547 
00548    //Debug message
00549    TRACE_DEBUG("DSA signature verification...\r\n");
00550    TRACE_DEBUG("  p:\r\n");
00551    TRACE_DEBUG_MPI("    ", &key->p);
00552    TRACE_DEBUG("  q:\r\n");
00553    TRACE_DEBUG_MPI("    ", &key->q);
00554    TRACE_DEBUG("  g:\r\n");
00555    TRACE_DEBUG_MPI("    ", &key->g);
00556    TRACE_DEBUG("  y:\r\n");
00557    TRACE_DEBUG_MPI("    ", &key->y);
00558    TRACE_DEBUG("  digest:\r\n");
00559    TRACE_DEBUG_ARRAY("    ", digest, digestLength);
00560    TRACE_DEBUG("  r:\r\n");
00561    TRACE_DEBUG_MPI("    ", &signature->r);
00562    TRACE_DEBUG("  s:\r\n");
00563    TRACE_DEBUG_MPI("    ", &signature->s);
00564 
00565    //The verifier shall check that 0 < r < q and 0 < s < q. If either
00566    //condition is violated, the signature shall be rejected as invalid
00567    if(mpiCompInt(&signature->r, 0) <= 0 || mpiComp(&signature->r, &key->q) >= 0)
00568       return ERROR_INVALID_SIGNATURE;
00569    if(mpiCompInt(&signature->s, 0) <= 0 || mpiComp(&signature->s, &key->q) >= 0)
00570       return ERROR_INVALID_SIGNATURE;
00571 
00572    //Initialize multiple precision integers
00573    mpiInit(&w);
00574    mpiInit(&z);
00575    mpiInit(&u1);
00576    mpiInit(&u2);
00577    mpiInit(&v);
00578 
00579    //Let N be the bit length of q
00580    n = mpiGetBitLength(&key->q);
00581    //Compute N = MIN(N, outlen)
00582    n = MIN(n, digestLength * 8);
00583 
00584    //Convert the digest to a multiple precision integer
00585    MPI_CHECK(mpiReadRaw(&z, digest, (n + 7) / 8));
00586 
00587    //Keep the leftmost N bits of the hash value
00588    if(n % 8)
00589    {
00590       MPI_CHECK(mpiShiftRight(&z, 8 - (n % 8)));
00591    }
00592 
00593    //Compute w = s ^ -1 mod q
00594    MPI_CHECK(mpiInvMod(&w, &signature->s, &key->q));
00595    //Compute u1 = z * w mod q
00596    MPI_CHECK(mpiMulMod(&u1, &z, &w, &key->q));
00597    //Compute u2 = r * w mod q
00598    MPI_CHECK(mpiMulMod(&u2, &signature->r, &w, &key->q));
00599 
00600    //Compute v = ((g ^ u1) * (y ^ u2) mod p) mod q
00601    MPI_CHECK(mpiExpMod(&v, &key->g, &u1, &key->p));
00602    MPI_CHECK(mpiExpMod(&w, &key->y, &u2, &key->p));
00603    MPI_CHECK(mpiMulMod(&v, &v, &w, &key->p));
00604    MPI_CHECK(mpiMod(&v, &v, &key->q));
00605 
00606    //Debug message
00607    TRACE_DEBUG("  v:\r\n");
00608    TRACE_DEBUG_MPI("    ", &v);
00609 
00610    //If v = r, then the signature is verified. If v does not equal r,
00611    //then the message or the signature may have been modified
00612    if(!mpiComp(&v, &signature->r))
00613       error = NO_ERROR;
00614    else
00615       error = ERROR_INVALID_SIGNATURE;
00616 
00617 end:
00618    //Release multiple precision integers
00619    mpiFree(&w);
00620    mpiFree(&z);
00621    mpiFree(&u1);
00622    mpiFree(&u2);
00623    mpiFree(&v);
00624 
00625    //Return status code
00626    return error;
00627 }
00628 
00629 #endif
00630